-- SPDX-License-Identifier: GPL-3.0-or-later
---@class LangAI: AI
-- InvaliditySkill = require "lua.core.skill_type.invalidity"
-- ProhibitSkill = require "core.skill_type.prohibit"
---------------------------此AI脚本针对军八卡组，浪系列卡组进行优化，其他加入卡组需要在下面配置表和写对应逻辑实现----------------------------
local BasicAI = require "packages/fkpve/AI/BasicAi"
---
local LangAI = BasicAI:subclass("LangAI")
local AiSkillsData = require "packages/fkpve/AI/AISkillsData"
LangAI.ISTRUE = true --没什么意义，确认该配表技能名的存在
LangAI.ISFALSE = false 
LangAI.ISFRIEND = "friend" --针对队友的技能配表（配置表看下方）
LangAI.ISENEMY = "enemy" --针对敌人的技能配表
LangAI.INVOKENORMAL = 1 --询问技，通过配表来分辨敌友是否发动
LangAI.INVOKESPECIAL = 2 --询问技，单独用表写函数实现对应逻辑（invokeBySpec表）
--目标身份是否和ai同一个阵营
LangAI.CAMPS = {lord = 1,loyalist = 1,rebel = 2,renegade = 3} 
LangAI.ISSAMECAMP = function(player,target)
  return LangAI.CAMPS[player.role] == LangAI.CAMPS[target.role]
end
--回血或濒死回血卡牌
LangAI.RECCARDS = {analeptic=LangAI.ISTRUE,peach=LangAI.ISTRUE}
--给表属性计数
LangAI.CNTTNUM = function(tb) 
  local n = 0
  if not next(tb) then
    return n
  end
  for k,v in pairs(tb) do
    n = n + 1
  end
  return n
end
--检测目标是否有某类型技能
LangAI.CheckStatusSkill = function(tar,skilltype,usecard,from,objfunc)
  if from and from.mark["df_fengkuang"] and from.mark["df_fengkuang"] ~= 0 then return false end
  for _, s in ipairs(tar.player_skills) do
    if s:isInstanceOf(skilltype) then
      if not usecard then return true end
      if usecard and from and s[objfunc] and s[objfunc](s,from,tar,usecard) then return true end
    else
      if #s.related_skills > 0 then
        for i, rela_s in ipairs(s.related_skills) do
          if rela_s:isInstanceOf(skilltype) then
            if not usecard then return true end
            if usecard and from and rela_s[objfunc] and rela_s[objfunc](rela_s,from,tar,usecard) then return true end
          end
        end
      end
    end
  end
  return false
end
--普遍卖血技能（遗迹，称象等）
LangAI.CellBlood = function(player,damage)
  local hands = player.player_cards[Player.Hand]
  if player.hp == player.maxHp then 
    return player.hp + #table.filter(hands,function(cid) return LangAI.RECCARDS[Fk:getCardById(cid).name] end) > damage
  end
  if (player.hp - damage) / player.maxHp < 0.7 then
    local peachs,analeptics = 0,0
    for _,cid in ipairs(hands) do
      local card = Fk:getCardById(cid)
      if not player:prohibitUse(card) then 
        if card.name == "peach" then 
          peachs = peachs + 1 
        end
        if card.name == "analeptics" then 
          analeptics = analeptics + 1 
        end
      end
    end
    if player.hp > 1 then
      return damage <= peachs
    else
      return damage <= peachs + analeptics
    end
  else
    return true
  end
end
----------------------AI技能配置表，让ai技能指向目标更合理（同名技能只写后缀真名，一般是“__”后面的拼音。比如想要写入界郭嘉的遗迹：ex__yiji,那只要写后缀yiji）-----------------------------
--技能黑名单，让一些技能永远不发动
LangAI.BLACKSKILLS = AiSkillsData:getBlackSkills()
--技能选项根据敌友目标选择合理选项（不用真名，优先找mustchose）
LangAI.SKILLCHOICE = AiSkillsData:getSkillChoice()
--让主动技能在出牌前先发动，默认是把牌出完后才发动
LangAI.USESKILLPRIO = AiSkillsData:getUseSkillPrio()
--最不优先攻击的技能列表
LangAI.WEEKATKSKILLS = AiSkillsData:getWeekAtkSkills()
--针对敌人的技能表
LangAI.SELENEMYBYCHOOSE = AiSkillsData:getSelEnemyByChoose()
--针对队友的技能表
LangAI.SELFRIENDBYCHOOSE = AiSkillsData:getSelFriendByChoose()
--询问技能是否发动（技能指向目标skilltar=LangAI.ISFRIEND是向队友发动，skilltar = LangAI.ISENEMY向敌人发动。如果促使发动技能的来源目标是队友且不对队友发动后面补isjudge=true，例如：贞烈）
LangAI.INVOKESKILL = AiSkillsData:getInvokeSkills()
--触发选牌技，让一些技能选择取消对ai比较友好
LangAI.CANCELSELCARD = AiSkillsData:getCanCelSelCard()
--不需要消耗牌的转化是为技
LangAI.NOCARDVSSkills = AiSkillsData:getNoCardVsSkills()
--出牌过程中用技能
LangAI.USESKILLBYPLAY = AiSkillsData:getUseSkillByPlay()
--用牌智能指向多人的技能
LangAI.MUTITARSBYCARD = AiSkillsData:getMutitarsByCard()
--卖血技能（优先受伤不出牌）
LangAI.DAMAGESKILLS = AiSkillsData:getDamageSkills()
--顶掉装备收益技能
LangAI.RepEquipSkills = AiSkillsData:getRepEquipSkills()
----------------------AI技能配置，让它更智能一些（同名技能只写后缀真名，一般是“__”后面的拼音。比如想要写入界郭嘉的遗迹：ex__yiji,那只要写后缀yiji）-----------------------------

----------------------------------------------可对diy牌名通过填表识别敌友-------------------------------------------
--ai针对敌人使用锦囊牌
local UseTricToEmy = {snatch = LangAI.ISTRUE,dismantlement = LangAI.ISTRUE,duel = LangAI.ISTRUE,supply_shortage = LangAI.ISTRUE,indulgence = LangAI.ISTRUE,slash = LangAI.ISTRUE,fire_attack = LangAI.ISTRUE,iron_chain = LangAI.ISTRUE}
--ai优先使用被记录的卡牌,必须是锦囊牌。
local UseRecordCards = {wdtx_lightning=LangAI.ISTRUE,snatch = LangAI.ISTRUE,dismantlement = LangAI.ISTRUE,iron_chain = LangAI.ISTRUE,supply_shortage = LangAI.ISTRUE,ljsy=LangAI.ISTRUE,ex_nihilo = LangAI.ISTRUE,duel = LangAI.ISTRUE,indulgence = LangAI.ISTRUE}
--延时锦囊牌（主要给改判技能用的，diy延时锦囊牌请在下方guicai函数里写对应逻辑）
local Delay_Cards = {indulgence=LangAI.ISTRUE,supply_shortage=LangAI.ISTRUE,lightning=LangAI.ISTRUE}
--移动判定区延时锦囊牌根据牌名执行优先顺序
local MoveDelaySeqs = {indulgence=1,supply_shortage=2} 
--ai优先拆敌人装备区武器列表
local DisEmyWeapons = {crossbow = true,axe = true,poisonous_dagger=true,quenched_blade=true,thunder_blade=true,fm_jingang=true,sw_feijiang=true}
--拆顺优先选敌人装备区的重要装备
local ImporEeuipsType = {Card.SubtypeDefensiveRide,Card.SubtypeArmor,Card.SubtypeTreasure,Card.SubtypeWeapon,Card.SubtypeOffensiveRide} 
--选牌或者弃牌牌名顺序根据配置来执行先后顺序(牌明越靠前越优先选择或弃之。装备统一用TypeEquip来替代)
local discards_prio_t = {"lightning","god_salvation","amazing_grace","collateral","supply_shortage","savage_assault","archery_attack","iron_chain","TypeEquip","dismantlement","snatch","duel","ex_nihilo","ljsy","indulgence","jink","nullification","slash","thunder__slash","fire__slash","analeptic","peach"}
local selcards_prio_t = {"indulgence","peach","analeptic","ljsy","ex_nihilo","duel","savage_assault","archery_attack","snatch","dismantlement","iron_chain","nullification","TypeEquip","jink","fire__slash","thunder__slash","slash","supply_shortage","collateral","god_salvation","amazing_grace","lightning"}
--使用武器的优先顺序（值越低优先级越高，优先级高的武器会顶掉低的,特殊装备如AK,火扇，青钢剑等根据杀的限制排除在外）
local UsePrioWeaponSeq = {axe=1,red_spear=0.8,quenched_blade=0.2,poisonous_dagger=0.1,water_sword=0.3,thunder_blade=0.4,fm_jingang=0.5,sw_feijiang=0.21,xyd_xueyingdao=0.6,blade=2,spear=3,kylin_bow=4,ice_sword=5,double_swords=6,guding_blade=7,halberd=8} 
local getPrioWeapon = function (self) --寻找最优先级武器
  local player = self.player
  local hands = self.handcards
  if #hands == 0 then return end
  local prios = {}
  for j = 1, #hands do
    local card = hands[j]
    if card.type == Card.TypeEquip and card.sub_type == Card.SubtypeWeapon and UsePrioWeaponSeq[card.trueName] then
      table.insert(prios,{UsePrioWeaponSeq[card.trueName],card})
    end
  end
  if #prios == 0 then return end
  table.sort(prios,function(a,b) return a[1] < b[1] end)
  if #prios > 0 then
    return prios[1]
  end
  return 
end
--使用卡牌的逻辑
LangAI.UseCardLogic = {}
LangAI.UseCardLogic["savage_assault"] = function(self,card)
  local vinenum = 0
  local player,room = self.player,self.player.room
  local otherplayers = room:getOtherPlayers(player)
  for _, pr in ipairs(otherplayers) do
    if pr:hasSkill("#vine_skill") and not LangAI.ISSAMECAMP(player,pr) then vinenum = vinenum + 1 end
    if LangAI.ISSAMECAMP(player,pr) and pr.hp < 2 and #pr.player_cards[Player.Hand] < 3 and not pr:hasSkill("#vine_skill") then return 0 end --打南万牌队友低体力少牌情况下不打牌
  end
  if vinenum == #otherplayers then return 0 end
  return card
end
LangAI.UseCardLogic["fire_attack"] = function(self,card)
   return #self.player.player_cards[Player.Hand] < 3 and 0 or card
end
LangAI.UseCardLogic["archery_attack"] = function(self,card)
  return LangAI.UseCardLogic["savage_assault"](self,card)
end
LangAI.UseCardLogic["god_salvation"] = function(self,card)
  local damfris,damemy = {},{}
  local player,room = self.player,self.player.room
  for _,pr in ipairs(room.alive_players) do
    if pr:isWounded() then
      if LangAI.ISSAMECAMP(player,pr) then 
        table.insert(damfris,pr.id) 
      else
        table.insert(damemy,pr.id)
      end
    end
  end
  if #damfris > #damemy or (player.hp < 3 and #damemy - #damfris <= 1) then return card end
  return 0
end
--获得敌我阵营玩家{player}
LangAI.GetPlayersByCamp = function(player,seltars,camp)
  if #seltars == 0 then return {} end
  local tars = {}
  local room = player.room
  local isids = type(seltars[1]) == "number" and true or false
  for _,pr in ipairs(seltars) do
    local tar = isids and room:getPlayerById(pr) or pr
    if LangAI.ISFRIEND == camp and LangAI.ISSAMECAMP(player,tar) then table.insert(tars,tar) end
    if LangAI.ISENEMY == camp and not LangAI.ISSAMECAMP(player,tar) then table.insert(tars,tar) end
  end
  return tars
end
----------------------------------------------ai对diy卡组填表识别敌友-------------------------------------------

--某些技能（例如：破军）用杀对目标护具可移除或者无视
local InDealArmSkills = {["#qinggang_sword_skill"]=LangAI.ISTRUE,["#poisonous_dagger_skill"]=LangAI.ISTRUE,tieqi=LangAI.ISTRUE,pojun=LangAI.ISTRUE,juelie=LangAI.ISTRUE,l_tuxi=LangAI.ISTRUE,xianzhen=LangAI.ISTRUE,qizhi=LangAI.ISTRUE}
local armordJudge = function (armname,player,card) 
  if armname == "nioh_shield" and card.color == Card.Black and table.every(player.player_skills,function(s) if not InDealArmSkills[s.trueName] then return true end end) then
    return true
  end
  if armname == "vine" and card.name == "slash" and not player:hasSkill("#fan_skill") and table.every(player.player_skills,function(s) if not InDealArmSkills[s.trueName] then return true end end) then
    return true
  end
  --if armname == "eight_diagram" and not player:hasSkill("#qinggang_sword_skill") and not player:hasSkill("m_ex__pojun") and not player:hasSkill("juelie") then
    --return true
  --end
  return false
end
local getSelCardsSeq = function(cards,sel_num,selcards_seq,nodiscart_t)
  if #cards == 1 or #cards == sel_num then return cards end
  local room = Fk:currentRoom()
  local cardsdata = {TypeEquip={}}
  local discard_t = {}
  for k,v in ipairs(cards) do
    local card = Fk:getCardById(v)
    if card.type ~= Card.TypeEquip then
      local cdata = cardsdata[card.name]
      if cdata then
        table.insert(cdata,card)
      else
        cardsdata[card.name] = {card}
      end
    else
      if room:getCardArea(v) ~= Card.PlayerEquip then
        table.insert(cardsdata.TypeEquip,card)
      end
    end
  end
  local n = 0
  while #discard_t ~= sel_num do
    for k,cname in ipairs(selcards_seq) do
      local cdatas = cardsdata[cname]
      if cdatas and #cdatas > 0 then
        local selcard = table.remove(cdatas)
        if not nodiscart_t then
          table.insert(discard_t,selcard.id)
          table.removeOne(cards,selcard.id)
          break
        else
          if not nodiscart_t[selcard.name] then
            table.insert(discard_t,selcard.id)
            table.removeOne(cards,selcard.id)
            break
          end
        end
        if #discard_t == sel_num then break end
      end
    end
    n = n + 1
    if n > sel_num then break end
  end
  if #discard_t ~= sel_num then
    local rerands = table.random(cards,sel_num-#discard_t)
    table.insertTable(discard_t,rerands)
    cardsdata = nil
    return discard_t
  else
    cardsdata = nil
    return discard_t
  end
end
--移动装备牌根据装备类型执行优先顺序
local MoveEQSeqs = {Card.SubtypeTreasure,Card.SubtypeDefensiveRide,Card.SubtypeArmor,Card.SubtypeWeapon,Card.SubtypeOffensiveRide} 
local getJudegeData = function(player)
  local judeges = player:getCardIds(Player.Judge)
  local data = {}
  for delay_c, v in pairs(MoveDelaySeqs) do
    for _, id in ipairs(judeges) do
      local c = player:getVirualEquip(id)
      if not c then c = Fk:getCardById(id) end
      if delay_c == c.trueName then
        table.insert(data,{delay_c,id}) 
      end
    end
  end
  return #data > 0 and data[1] or {}
end
--优先拆队友判定区的卡。优先找队友的兵乐(拆顺戏子的筹测)
local prioDismanFriArea = function(player)
  local room = player.room
  local friendtar,movetrick,moveid
  for _,pr in ipairs(room.alive_players) do
    if LangAI.ISSAMECAMP(player,pr) then
      if #pr.player_cards[Player.Judge] > 0 then 
        local mes = getJudegeData(pr)
        if #mes > 0 then friendtar = pr.id movetrick = mes[1] moveid = mes[2] break end
      end
    end
  end
  return friendtar and {friendtar,movetrick,moveid} or nil
end
--卡组里匹配对应条件的卡
local patByCards = function(avail_cards,patstr,num)
  local exp = Exppattern:Parse(patstr)
  local explist = table.filter(avail_cards,function(cid) 
    local card = Fk:getCardById(cid)
    if exp:match(card) then return true end
  end)
  if #explist == 0 then return end
  explist = getSelCardsSeq(explist,num,discards_prio_t)
  return explist
end
--处理room接口的prompt字符串主要是获取目标角色id
local getPlayerIdByPromt = function(data) 
  if not data then return end
  local last,isai,id
  if string.find(data,":%d") then
    last = string.find(data,":%d") + 1
  elseif string.find(data,":-%d") then
    last = string.find(data,":-%d") - 1
    isai = true
  end
  if last then
    local endlast = isai and last + 1 or last
    local n1 = tonumber(string.sub(data,last,endlast))
    local n2 = last  ~= #data and tonumber(string.sub(data,last,endlast+1)) or nil
    id = (n1 and n2) and n2 or n1
  end
  return id
end
--刷新技能信息（可以使用杀次数以及自身视为技）
local slashmax = {paoxiao = true,["#crossbow_skill"] = true,dulie=true} --找不到杀无限制的属性伪实现
local upSkillsInfo = function (self) 
  self.upmaxslash = false
  self.repequip = false
  self.weekAtkPids = {}
  local player,room = self.player,self.player.room
  local maxslashskill = false
  for _,s in ipairs(player.player_skills) do
    if slashmax[s.trueName or s.name] then maxslashskill = true end
    if LangAI.RepEquipSkills[s.trueName or s.name] then self.repequip = true end
  end
  local oplayers = {}
  for _, op in ipairs(room.alive_players) do
    if not LangAI.ISSAMECAMP(player,op) then
      table.insert(oplayers,op)
    end
  end
  for _, op in ipairs(oplayers) do
    for i,s in ipairs(op.player_skills) do
      if LangAI.WEEKATKSKILLS[s.trueName] then
        table.insert(self.weekAtkPids,op.id)
      end
    end
  end
  
  if maxslashskill then
    self.totalslash = 999
  else
    local c = Fk:cloneCard("slash")
    self.totalslash = c.skill:getMaxUseTime(player, Player.HistoryPhase,c ,player)
  end
end
--可以使用装备
local canUseEquip = function(player,card)
  return not player:prohibitUse(card) and not table.contains(player.sealedSlots,Util.convertSubtypeAndEquipSlot(card.sub_type))
end
--获取手里指定牌名的装备id
local getHandEuipId = function (self,subtype,name) 
  local player = self.player
  local hands = self.handcards
  if #hands == 0 then return end
  for j = 1, #hands do
    local card = hands[j]
    if card.type == Card.TypeEquip and card.sub_type == subtype and card.name == name and canUseEquip(player,card) then
      return card.id
    end
  end
  return
end
--根据敌人护具使用克制武器
local useDealWeapon = function (self,name)
  local euip = getHandEuipId(self,Card.SubtypeWeapon,name)
  if euip then
    if name == "crossbow" then
      upSkillsInfo(self)
    end
    return json.encode{
      card = euip,
      targets = {},
    }
  end
  return
end
--寻找最长攻击范围武器
local getAtkRangeMax = function (self) 
  local player = self.player
  local hands = self.handcards
  if #hands == 0 then return end
  local attack_range = 0
  local equipid
  for j = 1, #hands do
    local card = hands[j]
    if card.type == Card.TypeEquip and card.sub_type == Card.SubtypeWeapon and card.attack_range > attack_range and canUseEquip(player,card) then
      equipid = card.id
      attack_range = card.attack_range
    end
  end
  if equipid then
    return json.encode{
      card = equipid,
      targets = {},
    }
  end
  return 
end

local CardFilterHandle = function (player,card,fiterskills) --在手里的牌被动视为其他牌名的视为技处理
  if #fiterskills == 0 then
    return card
  end
  local cardid = card.id
  for _, skill in ipairs(fiterskills) do
    if skill:cardFilter(card,player) then
      local cd = skill:viewAs(card,player)
      if cd then
        cd.originid = cardid
        return cd
      end 
    end
  end
  return card
end

--使用杀判断防具
local CanPlaySlash = function (card,player,armor)
  local arm = Fk:getCardById(armor)
  if armordJudge(arm.trueName,player,card) then
    return false
  end
  return true
end

local tarArmorHandle = {} --处理敌人防具使用对应武器来对付
tarArmorHandle["nioh_shield"] = function (self,card,player)  --寻找使用对付的武器
  if armordJudge("nioh_shield",player,card) then
    local result = useDealWeapon(self,"qinggang_sword")
    return result and result or "none"
  end
  return "canslash"
end
tarArmorHandle["eight_diagram"] = function (self,card,player)  --寻找使用对付的武器
  --if armordJudge("eight_diagram",player,card) then
    local result = useDealWeapon(self,"qinggang_sword")
    return result and result or "canslash"
  --end
  --return "canslash"
end
tarArmorHandle["vine"] = function (self,card,player) 
  if armordJudge("vine",player,card) then
    local result = useDealWeapon(self,"fan")
    if not result then
      local result = useDealWeapon(self,"qinggang_sword")
      return result and result or "none"
    end
    return result and result or "none"
  end
  return "canslash"
end
tarArmorHandle["silver_lion"] = function (self,card,player) 
  -- if player.drank == 1 and not player:hasSkill("#qinggang_sword_skill") then
  --   local rest = useDealWeapon(self,"qinggang_sword")
  --   return rest
  -- end
  if self.totalslash ~= 999 then
    local result = useDealWeapon(self,"crossbow")
    return result and result or "canslash"
  end
  return "canslash"
end

local fiterTarHanle
fiterTarHanle = function (selected_targets,targets,weekAtkPids,prioid)
  if prioid then
    local prio = table.find(targets,function (id) 
      if prioid == id then
        return true
      end
    end)
    if prio then return {prioid} end
  end
  local rightpid = table.remove(targets,1)
  if not table.contains(weekAtkPids,rightpid) and not table.contains(selected_targets,rightpid) then
    table.insert(selected_targets,rightpid)
  else
    if #targets > 0 then
      return fiterTarHanle(selected_targets,targets,weekAtkPids)
    end
    table.insert(selected_targets,rightpid)
  end
  return selected_targets
end
--使用牌检查是否有主动视为技能打出某个牌名
local needCardSkill = function(self,cname) 
  local player = self.player
  if LangAI.USESKILLBYPLAY[cname] then
    local cnskills = LangAI.USESKILLBYPLAY[cname]
    local ski = table.find(player.player_skills,function(s)
      if cnskills[s.trueName] then return true end
    end)
    return ski
  end
end
--打牌过程需要某种牌名的主动视为技（一般是用酒）
local useSelfVsCards = function(player,skill,vsname,isnocard) 
  if isnocard then
    return json.encode{
      card = json.encode{
        skill = skill.name,
        subcards = {},
      },
      targets = {},
    }
  end
  local max_try_time = 2
  local selected_cards = {}
  local pattern = skill.pattern
  local pcards = player:getCardIds({Player.Hand,Player.Equip})
  local exp = Exppattern:Parse(pattern or ".")
  if skill.interaction then
    if next(skill.interaction) == nil then  --初始化太操蛋了
      local interaction = skill:interaction()
      -- skill.interaction = interaction or {}
      skill.interaction.data = vsname
    else
      skill.interaction.data = vsname
    end
  end
  for _ = 0, max_try_time do
    local avail_cards = table.filter(pcards, function(id)
      local card = Fk:getCardById(id)
      return skill:cardFilter(id, selected_cards) and exp:match(card) and not player:prohibitUse(card)
    end)
    if #avail_cards == 0 then break end
    local randcard = table.random(avail_cards)
    table.removeOne(pcards,randcard)
    table.insertIfNeed(selected_cards, randcard)
    local ascard = skill:viewAs(selected_cards)
    if ascard then
      local ret = json.encode{
        card = json.encode{
          skill = skill.name,
          subcards = selected_cards,
        },
        targets = {},
        interaction_data = vsname
      }
      return ret
    end
  end
  return nil
end
local EncodeByPlayCard = function(card,tars,skillname)
  return json.encode{
    card = skillname and json.encode{skill = skillname,subcards = card.id ~= 0 and {card.id} or card.subcards} or (card.id ~= 0 and card.id or card.originid),
    targets = tars or {}
  }
end
--打牌识别敌友及其牌特性逻辑的函数
local function PlayCards(self, skill, card, isview)
  local room = self.room
  local player = self.player
  local max_try_times = 1
  local maxtars = skill.getMaxTargetNum and skill:getMaxTargetNum(player, card) or 1
  local hasvine
  local selected_targets = {}
  local selected_cards = {}
  local playtars = {}
  local aliveplayers = room:getAlivePlayers()
  for _ = 0, max_try_times do
    if skill:feasible(selected_targets, selected_cards, player, card) then break end --使用牌指向的目标是否符合技能条件
    local avail_targets = table.filter(aliveplayers, function(p)
      if UseTricToEmy[card.trueName] and LangAI.ISSAMECAMP(player,p) then --伤害控制牌优先过滤掉相同阵营目标
        return false
      end
      local ret = skill:targetFilter(p.id, selected_targets, selected_cards, card) --使用牌指向的目标是否合法
      if not ret then return false end
      if LangAI.CheckStatusSkill(p,ProhibitSkill,card,player,"isProhibited") then return false end
      --拆顺对面要有手牌
      if (card.trueName == "dismantlement" or card.trueName == "snatch") and p:isNude() then return false end
      if card.trueName == "fire_attack" and p:isKongcheng() then return false end
      --乐兵对面要没有乐兵
      if card.sub_type == Card.SubtypeDelayedTrick and p:hasDelayedTrick(card.trueName) then return false end
      --火攻优先找藤甲
      if card.trueName == "fire_attack" and p:hasSkill("#vine_skill") then
        hasvine = p.id
      end
      return ret
    end)
    if #avail_targets == 0 then 
      if card.trueName == "slash" and player:usedCardTimes("slash",Player.HistoryPhase) == 0 and not isview then  --用杀可能攻击距离不够找攻击距离最长的武器
        local result = getAtkRangeMax(self)
        if result then return result end
      end
      return 
    end
    --排序目标
    table.sort(avail_targets,function (a,b) return a.hp < b.hp end)
    if card.trueName == "indulgence" then
      table.sort(avail_targets,function (a,b) return #a.player_cards[Player.Hand] > #b.player_cards[Player.Hand] end)
    end
    local targets = table.map(avail_targets,Util.IdMapper)
    selected_targets = fiterTarHanle(selected_targets,table.clone(targets),self.weekAtkPids,hasvine)
    local selted_tar = room:getPlayerById(selected_targets[1])
    table.removeOne(targets,selected_targets[1])
    table.removeOne(avail_targets,selted_tar)
    playtars = table.clone(targets)
    --铁索连环对象只有一个或者选中的对象被横置则重置
    if card.trueName == "iron_chain" then
      if #avail_targets > 0 then
        local randtar = table.random(avail_targets)
        if selted_tar.chained or randtar.chained then
          return EncodeByPlayCard(card,{},"recast")
        end
        table.insert(selected_targets,randtar.id)
      else
        return EncodeByPlayCard(card,{},"recast")
      end
    end
    local remainnum = maxtars - #selected_targets 
    if card.trueName == "slash" and #targets > 0 and remainnum > 0 then
      local tarnum = math.min(#targets,remainnum)
      for i = 1, tarnum do
        local randpid = table.random(targets)
        table.insert(selected_targets,randpid)
        table.removeOne(targets,randpid)
      end
    end
  end
  if skill:feasible(selected_targets, selected_cards, self.player, card) then
    if isview then return selected_targets end --给回合外视为技卡牌指定对象用的
    if card.trueName == "slash" then --用杀逻辑(在攻击范围内)
      local p = room:getPlayerById(selected_targets[1])
      local eid = p and p:getEquipment(Card.SubtypeArmor)
      if eid then --出杀对目标有防具判断
        local ecard = Fk:getCardById(eid)     
        local armhandle = tarArmorHandle[ecard.trueName]  --识别对方防具
        if armhandle then
          local result = armhandle(self,card,player)
          if result == "none" then  --没有武器那就找其他人杀
            if #playtars == 0 then return end
            selected_targets = {table.random(playtars)}
          end
          if result ~= "canslash" and result ~= "none" then return result end
        end
        local ecid = player:getEquipment(Card.SubtypeWeapon)
        if not ecid then
          local result = getAtkRangeMax(self)
          if result then return result end
        end
      else
        local ecid = player:getEquipment(Card.SubtypeWeapon) 
        if not ecid then
          local result = useDealWeapon(self,"crossbow")  --寻找ak
          if result then 
            return result 
          else
            local result = getAtkRangeMax(self)
            if result then return result end
          end
        else
          local myeuip = Fk:getCardById(ecid)  
          local ismyatkrang = p and player:inMyAttackRange(p,-myeuip.attack_range + 1)
          if ismyatkrang and self.reslash - 1 <= 0 then --换下武器用ak是不是也在我攻击范围呢
            local result = useDealWeapon(self,"crossbow")
            if result then return result end
          end
        end
      end
      --最后有杀且最后1次杀之前喝酒
      if self.use_analep then
        local analep = Fk:getCardById(self.use_analep,true)
        return analep and EncodeByPlayCard(analep,{})
      else --没有酒但是有用酒相关的技能
        local analep = "analeptic"
        local anaski = needCardSkill(self,analep)
        if anaski and anaski.enabledAtPlay and anaski:enabledAtPlay(player) and player.drank == 0 then
          local uc = Fk:cloneCard(analep)
          if player:canUse(uc) then
            local ret = useSelfVsCards(player, anaski,analep,LangAI.NOCARDVSSkills[anaski.trueName])
            if ret then return ret end
          end
        end
      end
    end
    return EncodeByPlayCard(card,selected_targets)
  end
  return
end

---@param self LangAI
---@param skill ActiveSkill
---@param card Card | nil
local handleNum = function (skill,num)
  if not num then return end
  if type(num) == "number" then
    if num >= 99 then return end
    return num
  elseif type(num) == "function" then
    return num(skill)
  end
end
--主动技选人，（选牌还得优化）
local function useActiveSkill(self, skill, card)
  local room = self.room
  local player = self.player
  --技能选项数据初始化
  if skill.interaction then
    if next(skill.interaction) == nil then  --初始化太操蛋了
      local interaction = skill:interaction()
      skill.interaction = interaction
      if skill.interaction.type == "spin" then
        skill.interaction.data = math.floor(math.random(interaction.from,interaction.to))
      elseif skill.interaction.type == "combo" then
        skill.interaction.data = skill.trueName ~= "guose" and table.random(interaction.all_choices) or "ex__guose_use"
      end
    else
      if skill.interaction.type == "spin" then
        skill.interaction.data = math.floor(math.random(skill.interaction.from,skill.interaction.to))
      elseif skill.interaction.type == "combo" then
        skill.interaction.data = skill.trueName ~= "guose" and table.random(skill.interaction.all_choices) or "ex__guose_use"
      end
    end
  end

  local tcards = table.clone(player:getCardIds{ Player.Hand, Player.Equip }) 
  if skill.expand_pile and player:getPile(skill.expand_pile) and #player:getPile(skill.expand_pile) > 0 then
    tcards = table.clone(player:getPile(skill.expand_pile))
  end
  if skill.name == "ty_ex__paiyi" then  --十周年排异专属优化
    if #tcards ==0 or not skill:canUse(player) then return end
    local drawphase = player:getMark("ty_ex__paiyi_draw-phase")
    local damagephase = player:getMark("ty_ex__paiyi_damage-phase")
    if drawphase == 0 then
      skill.interaction.data = "ty_ex__paiyi_draw"
      return json.encode{
        card = json.encode{
          skill = skill.name,
          subcards = table.random(tcards,1),
        },
        targets = {player.id},
        interaction_data = skill.interaction.data
      }
    end
    if damagephase == 0 then
      local tarenemys = table.filter(room:getOtherPlayers(player),function(pr)
      if not LangAI.ISSAMECAMP(player,pr) then
        return true
      end
      end)
      if #tarenemys == 0 then return end
      skill.interaction.data = "ty_ex__paiyi_damage"
      local mincardstars = math.min(#tarenemys,#tcards)
      tarenemys = table.map(tarenemys,Util.IdMapper)
      return json.encode{
        card = json.encode{
          skill = skill.name,
          subcards = table.random(tcards,mincardstars),
        },
        targets = table.random(tarenemys,mincardstars),
        interaction_data = skill.interaction.data
      }
    end
  end
  local maxtars = handleNum(skill,skill.max_target_num) or handleNum(skill,skill.target_num) or handleNum(skill,skill.min_target_num)
  -- local maxcards = handleNum(skill,skill.max_card_num) or handleNum(skill,skill.card_num) or handleNum(skill,skill.min_card_num)
  local maxcards,maxtype
  if skill.card_num then
    if type(skill.card_num) == "number" then
      maxcards = skill.card_num <= 99 and skill.card_num or nil
    elseif type(skill.card_num) == "function" then
      local skillnum = skill:card_num()
      maxcards = skillnum <= 99 and skillnum or nil
    end
  end
  if not maxcards then
    if skill.max_card_num then
      if type(skill.max_card_num) == "number" then
        maxcards = skill.max_card_num > 99 and #tcards or skill.max_card_num
      elseif type(skill.max_card_num) == "function" then
        local skillnum = skill:max_card_num()
        maxcards = skillnum > 99 and #tcards or skillnum
      end
    end
    maxtype = 2
  else
    maxtype = 1
  end

  local alivePlayers = room:getAlivePlayers()
  local max_try_times = 3
  local selected_targets = {}
  local selected_cards = {}
  for _ = 0, max_try_times do
    if skill:feasible(selected_targets, selected_cards, self.player, card) then break end
    local avail_targets = table.filter(alivePlayers, function(p)
      local ret = skill:targetFilter(p.id, selected_targets, selected_cards, card or Fk:cloneCard'zixing')
      if not ret then return false end
      if LangAI.SELENEMYBYCHOOSE[skill.trueName] and LangAI.ISSAMECAMP(player,p) then  --面板上按主动技选人或者选牌
        ret = false
      end
      if LangAI.SELFRIENDBYCHOOSE[skill.trueName] and not LangAI.ISSAMECAMP(player,p) then
        ret = false
      end
      return ret
    end)
    --筛选卡牌
    local avail_cards = {}
    if maxcards and maxcards > 0 and maxcards ~= #selected_cards then
      for i = 1, math.min(#tcards,4) do
        if #tcards == 0 then break end
        local availcard = table.find(tcards, function(id)
          return skill.cardFilter(skill,id, avail_cards,selected_targets)
        end)
        if maxtype and maxtype == 1 and availcard then  --固定选卡数量
          table.insert(avail_cards,availcard)
          table.removeOne(tcards,availcard)
          if #avail_cards == maxcards then break end
        end
        if maxtype and maxtype == 2 then    --最大选卡数量
          if availcard then
            table.insert(avail_cards,availcard)
            table.removeOne(tcards,availcard)
          else
            break
          end
        end
      end
    end
    if #avail_targets == 0 and #avail_cards == 0 then break end
    --排序目标
    table.sort(avail_targets,function (a,b) return a.hp < b.hp end)
    local targets = table.map(avail_targets,Util.IdMapper)
    selected_targets = fiterTarHanle(selected_targets,table.clone(targets),self.weekAtkPids)
    local selted_tar = room:getPlayerById(selected_targets[1])
    table.removeOne(targets,selected_targets[1])
    table.removeOne(avail_targets,selted_tar)
    --筛选卡牌
    table.insertTable(selected_cards, avail_cards) 
    --目标与选牌最大化
    if maxtars then
      local remainnum = maxtars - #selected_targets 
      if #targets > 0 and remainnum > 0 then
        local tarnum = math.min(#targets,remainnum)
        for i = 1, tarnum do
          local randpid = table.random(targets)
          table.insert(selected_targets,randpid)
          table.removeOne(targets,randpid)
        end
      end
    end
  end
  if skill:feasible(selected_targets, selected_cards, self.player, card) then
    local ret = json.encode{
      card = json.encode{
        skill = skill.name,
        subcards = selected_cards,
      },
      targets = selected_targets,
      interaction_data = skill.interaction and (next(skill.interaction) and skill.interaction.data or nil) or nil
    }
    -- print(ret)
    return ret
  end
  return
end

---@param self LangAI
---@param skill ViewAsSkill
--转化技（把符合条件某张卡转为指向卡）
local function useVSSkill(self, skill, pattern, viewname)
  local player = self.player
  local room = self.room
  local precondition
  if self.command == "PlayCard" and not Fk.currentResponsePattern then --出牌阶段使用转化技是根据pattern来检索可以使用的转化卡
    local gb = string.find(skill.pattern,",")
    if gb then
      gb = string.gsub(skill.pattern,",",";")
    else
      gb = skill.pattern
    end
    local exp = Exppattern:Parse(gb)
    local cnames = {}
    for _, m in ipairs(exp.matchers) do
      if m.trueName then table.insertTable(cnames, m.trueName) end
    end
    if (not gb or gb == "") and skill.interaction and next(skill.interaction) == nil then --类似欢乐荀攸技能，没有pattern但有转化选项
      local interaction = skill:interaction()
      local chcs = interaction and interaction.choices
      if chcs and #chcs > 0 then
        skill.interaction = interaction
        skill.interaction.data = table.random(chcs)
        precondition = skill.interaction.data
      end
    end
    if #cnames == 0 and not precondition then return end
    if #cnames > 0 then
      for _, n in ipairs(cnames) do
        local c = Fk:cloneCard(n)
        if c.trueName ~= "analeptic" then --出牌阶段在其他地方使用酒技能
          precondition = player:canUse(c) and c.trueName
          if precondition then break end
        end
      end
    end
  else --回合外使用转化技根据相应/使用匹配的卡来执行逻辑
    precondition = viewname
  end
  if not precondition then return nil end
  --转化卡选项数据初始化
  if skill.interaction then
    if next(skill.interaction) == nil then  --初始化太操蛋了
      local interaction = skill:interaction()
      local choices = (interaction and interaction.choices and #interaction.choices > 0) and interaction.choices or nil
      if not choices then return end
      skill.interaction.data = #choices > 0 and table.random(choices) or nil
    else
      if type(skill.interaction) == "table" then
        skill.interaction.data = nil
        local interaction = skill.name == "shouli" and Fk.skills[skill.name]:interaction() or skill.interaction
        local choices = (interaction and interaction.choices and #interaction.choices > 0) and interaction.choices or nil
        if not choices then return end
        skill.interaction.data = #choices > 0 and table.random(choices) or nil
      end
    end
    if skill.interaction.data then skill.interaction.data = precondition else return end
  end
  if LangAI.NOCARDVSSkills[skill.trueName] then --转化卡牌不需要真牌
   local ucard = skill:viewAs()
   if ucard then
    local t = PlayCards(self,ucard.skill,ucard,true)
    if t then
      if not viewname then
        return json.encode{
          card = json.encode{
            skill = skill.name,
            subcards = {},
          },
          targets = t,
          interaction_data = skill.interaction and skill.interaction.data or nil
        }
      else
        return {trueName = viewname,skillname = skill.name,selected_cards = {},selected_targets = t,interaction_data = skill.interaction and skill.interaction.data or nil}
      end
    end
   end
   return 
  end
  local selected_cards = {}
  local selected_targets = {}
  local max_try_time = 3
  local pcards = player:getCardIds{ Player.Hand, Player.Equip }
  if skill.expand_pile and player:getPile(skill.expand_pile) and #player:getPile(skill.expand_pile) > 0 then
    pcards = table.clone(player:getPile(skill.expand_pile))
  end
  for _ = 0, max_try_time do
    local avail_cards = table.filter(pcards, function(id)
      return skill:cardFilter(id, selected_cards)
    end)
    if #avail_cards == 0 then break end
    local randcard = table.random(avail_cards)
    table.removeOne(pcards,randcard)
    table.insertIfNeed(selected_cards, randcard)
    local ascard = skill:viewAs(selected_cards)
    if ascard and not player:prohibitUse(ascard) then
      if viewname then  --回合外视为技能对指定目标返回这个数据来匹配敌友策略
        return {trueName = viewname,skillname = skill.name,selected_cards = selected_cards,selected_targets = selected_targets,interaction_data = (skill.interaction and skill.interaction.data) and skill.interaction.data or nil}
      end
      local targets = PlayCards(self,ascard.skill,ascard,true)
      if targets then selected_targets = targets end
      if not targets and UseTricToEmy[ascard.trueName] then return end
      local ret = json.encode{
        card = json.encode{
          skill = skill.name,
          subcards = selected_cards,
        },
        targets = selected_targets,
        interaction_data = skill.interaction and (next(skill.interaction) and skill.interaction.data or nil) or nil
      }
      return ret
    end 
  end
  return
end

local random_cb = {}
local suit_type = {spade = Card.Spade,club = Card.Club,heart = Card.Heart,diamond = Card.Diamond}
--发送使用其他技能数据
local EnCodeByUseSkill = function(skillname,selcards,seltars,interaction_data)
  local scards = selcards or {}
  local stars = seltars or {}
  return json.encode{
    card = json.encode{
    skill = skillname,
    subcards = scards,
  },
    targets = stars,
    interaction_data = interaction_data or nil
  }
end
--专属优化技能
local singleOptiSkill = {}
--该diy技能函数涉及较多的room传递的技能类型数据，所以有些参数内容不同，需要根据下面random_cb接口参数做参考然后再diy
--self为当前人机脚本LangAI
--skill为技能
--promt为提示
--cancelable为可点击取消
--skillmes为技能的其他data
LangAI.DiySkillLogic = singleOptiSkill
LangAI.EnCodeByUseSkill = EnCodeByUseSkill
-- singleOptiSkill["bingzheng"] = function(self,skill,promt,cancelable,skillmes)
--   local player,room = self.player,self.player.room
--   local fritars = {}
--   local enytars = {}
--   if not skillmes then return "" end
--   for _,id in ipairs(skillmes.targets) do
--     local tar = room:getPlayerById(id)
--     if LangAI.ISSAMECAMP(player,tar) then
--       table.insert(fritars,tar)
--     else
--       table.insert(enytars,tar)
--     end
--   end
--   if #fritars > 0 then table.sort(fritars,function(a,b) return a.hp < b.hp end) return EnCodeByUseSkill(skill.name,{},{fritars[1].id}) end
--   if #enytars > 0 then table.sort(enytars,function(a,b) return #a.player_cards[Player.Hand] > #b.player_cards[Player.Hand] end) return EnCodeByUseSkill(skill.name,{},{enytars[1].id}) end
--   return ""
-- end
---------------回合内主动技优化（始）-----------------
singleOptiSkill["songci"] = function(self,skill,promt,cancelable,skillmes) 
  local player,room = self.player,self.player.room
  local seltars = {}
  for _,pr in ipairs(room.alive_players) do
    local ret = skill:targetFilter(pr.id, seltars)
    if ret then
      if LangAI.ISSAMECAMP(player,pr) and #pr.player_cards[Player.Hand] <= pr.hp then
        table.insert(seltars,pr.id)
        break
      end
      if not LangAI.ISSAMECAMP(player,pr) and #pr.player_cards[Player.Hand] > pr.hp then
        table.insert(seltars,pr.id)
        break
      end
    end
  end
  if #seltars > 0 then return EnCodeByUseSkill(skill.name,{},seltars) end
  return
end
singleOptiSkill["zunwei"] = function(self,skill,promt,cancelable,skillmes)  --尊位优化
  local player,room = self.player,self.player.room
  local interaction = skill:interaction()
  if #interaction.choices == 0 then return end
  local others = room:getOtherPlayers(player)
  local selchs,interactiondata
  -- skill.interaction.data = nil
  if table.contains(interaction.choices,"zunwei1") then
    table.sort(others,function(a,b) return #a.player_cards[Player.Hand] > #b.player_cards[Player.Hand] end)
    if #others[1].player_cards[Player.Hand] - #player.player_cards[Player.Hand] > 1 then interactiondata = "zunwei1" selchs = others[1].id end
  end
  if table.contains(interaction.choices,"zunwei2") and not selchs then
    table.sort(others,function(a,b) return #a.player_cards[Player.Equip] > #b.player_cards[Player.Equip] end)
    if #others[1].player_cards[Player.Equip] - #player.player_cards[Player.Equip] > 1 then interactiondata = "zunwei2" selchs = others[1].id end
  end
  if table.contains(interaction.choices,"zunwei3") and not selchs then
    table.sort(others,function(a,b) return a.hp > b.hp end)
    if others[1].hp - player.hp > 1 and player:isWounded() then interactiondata = "zunwei3" selchs = others[1].id  end
  end
  if interactiondata then
    return EnCodeByUseSkill(skill.name,{},{selchs},interactiondata)
  end
end
singleOptiSkill["jiwu"] = function(self,skill,promt,cancelable,skillmes) 
  local player,room = self.player,self.player.room
  local hands = player.player_cards[Player.Hand]
  if #hands == 0 then return end
  local interaction = Fk.skills[skill.name]:interaction()
  if not interaction then return end
  if not player:hasSkill("ol_ex__qiangxi") then
    -- skill.interaction.data = "ol_ex__qiangxi"
    local clonehands = table.clone(hands)
    return EnCodeByUseSkill(skill.name,getSelCardsSeq(clonehands,1,discards_prio_t),{},"ol_ex__qiangxi")
  end
  if not player:hasSkill("ex__tieji") then
    -- skill.interaction.data = "ex__tieji"
    local clonehands = table.clone(hands)
    return EnCodeByUseSkill(skill.name,getSelCardsSeq(clonehands,1,discards_prio_t),{},"ex__tieji")
  end
  if not player:hasSkill("ty_ex__xuanfeng") then
    -- skill.interaction.data = "ty_ex__xuanfeng"
    local clonehands = table.clone(hands)
    return EnCodeByUseSkill(skill.name,getSelCardsSeq(clonehands,1,discards_prio_t),{},"ty_ex__xuanfeng")
  end
  if not player:hasSkill("ol_ex__wansha") then
    local lowhper = table.find(room.alive_players,function(pr) return pr ~= player and pr.hp < 3 and not LangAI:ISSAMECAMP(pr,player) end)
    if lowhper then
      -- skill.interaction.data = "ol_ex__wansha"
      local clonehands = table.clone(hands)
      return EnCodeByUseSkill(skill.name,getSelCardsSeq(clonehands,1,discards_prio_t),{},"ol_ex__wansha")
    end
  end
end
singleOptiSkill["ex__yongjin"] = function(self,skill,promt,cancelable,skillmes) 
  local player,room = self.player,self.player.room
  local emys_equips = 0
  for _,pr in ipairs(room.alive_players) do
    if pr ~= player and not LangAI.ISSAMECAMP(player,pr) then
      local equips = pr.player_cards[Player.Equip]
      if #equips > 0 then
        for i,e in ipairs(equips) do
          if not table.contains(player.player_cards[Player.Equip],e) then
            emys_equips = emys_equips + 1
          end
        end
      end
    end
  end
  if emys_equips > 1 then
    return EnCodeByUseSkill(skill.name,{},{})
  end
  self.activeJumps[skill.name] = true
  return
end
---------------回合内主动技优化（末）-----------------

--拼点技能深度优化（来源dis_sel_cards技能优先单独优化）
singleOptiSkill["askforPinDian"] = function(self,skill,promt,cancelable,skillmes) 
  local player,room = self.player,self.player.room
  local num = skillmes.num
  local max = 0
  local id
  local hands = player:getCardIds{Player.Hand}
  if #hands == 0 then return "" end
  for _, cid in ipairs(hands) do
    local card = Fk:getCardById(cid)
    if card.number > max then
      max = card.number
      id = card.id
    end
  end
  return id and EnCodeByUseSkill(skill.name,{id},{}) or ""
end

--必选目标和选牌（例如秘技）
singleOptiSkill["miji"] = function(self,skill,promt,cancelable,skillmes) 
  local player,room = self.player,self.player.room
  local others = room:getOtherPlayers(player)
  local friend = table.find(others,function(pr) return LangAI.ISSAMECAMP(pr,player) end)
  local seltars = {friend and friend.id or table.random(others).id}
  local selcards = {table.random(player.player_cards[Player.Hand])}
  return EnCodeByUseSkill(skill.name,selcards,seltars)
end
--------其他技能处理数据（接口：AskForUseActiveSkill）----------
--------choose_players_skill通用处理（始）----------
singleOptiSkill["choose_players_skill"] = function(self,skill,promt,cancelable,skillmes)  --选择目标角色技能
  local player,room = self.player,self.player.room
  local tname = skillmes and skillmes.skillName and Fk.skills[skillmes.skillName] and Fk.skills[skillmes.skillName].trueName
  local num = skillmes.num or skillmes.min_num
  local pattern = skillmes.pattern
  local seltars = {}
  local selcards = {}
  local current = room.logic:getCurrentEvent()
  if LangAI.SELENEMYBYCHOOSE[tname] or LangAI.SELFRIENDBYCHOOSE[tname] or LangAI.MUTITARSBYCARD[tname] then
    local usecardtotar = {}
    if LangAI.MUTITARSBYCARD[tname] then --这是用牌指向多个目标的技能
      local usecard = current:findParent(GameEvent.UseCard,Self)
      if usecard then
        local datacard = usecard.data[1] and usecard.data[1].card
        if datacard then
          if (datacard.multiple_targets and datacard.is_damage_card) or datacard.trueName == "slash" then
            usecardtotar.totar = 2
          else
            local useret = PlayCards(self,datacard.skill,datacard,true)
            if useret then usecardtotar.totar = #useret == 0 and 1 or 2 end
          end
        end
      end
    end
    if pattern and pattern~="" then --非主动技选人又选牌的
      local hands = player:getCardIds{Player.Hand, Player.Equip}
      local exp = Exppattern:Parse(pattern)
      local cids = table.filter(hands,function (cid)
        local card = Fk:getCardById(cid)
        return exp:match(card)
      end)
      if #cids > 0 then
        cids = getSelCardsSeq(cids,1,discards_prio_t)
        table.insert(selcards,cids[1])
      end
    end
    for _, pid in ipairs(skillmes.targets) do
      if #seltars == num then break end
      local target = room:getPlayerById(pid)
      if LangAI.ISSAMECAMP(player,target) and LangAI.SELFRIENDBYCHOOSE[tname] then
        table.insertIfNeed(seltars,pid)
      end
      if not LangAI.ISSAMECAMP(player,target) and LangAI.SELENEMYBYCHOOSE[tname] then
        table.insertIfNeed(seltars,pid)
      end
      if usecardtotar.totar then
        if usecardtotar.totar == 1 and LangAI.ISSAMECAMP(player,target) then
          table.insertIfNeed(seltars,pid)
        end
        if usecardtotar.totar == 2 and not LangAI.ISSAMECAMP(player,target) then
          table.insertIfNeed(seltars,pid)
        end
      end
    end
    if #seltars > 0 then return EnCodeByUseSkill(skill.name,selcards,seltars) end
    return "" --如果没人那就返回""
  end
end

singleOptiSkill["bihuo"] = function(self,skill,promt,cancelable,skillmes)
  local player,room = self.player,self.player.room
  local secamp = promt == "#bihuo-plus" and LangAI.ISFRIEND or LangAI.ISENEMY
  local tars = LangAI.GetPlayersByCamp(player,room:getAlivePlayers(true),secamp)
  return #tars > 0 and EnCodeByUseSkill(skill.name,{},{tars[1].id}) or ""
end
singleOptiSkill["poxi"] = function(self,skill)
  local player,room = self.player,self.player.room
  local seltars = {}
  for _,pr in ipairs(room:getOtherPlayers(player)) do
    if not LangAI.ISSAMECAMP(player,pr) and #pr.player_cards[Player.Hand] > 0 then
      table.insert(seltars,pr)
    end
  end
  if #seltars > 0 then
    table.sort(seltars,function(a,b) return #a.player_cards[Player.Hand] > #b.player_cards[Player.Hand] end)
    return EnCodeByUseSkill(skill.name,{},{seltars[1].id})
  end
end
singleOptiSkill["fenwei"] = function(self,skill,promt,cancelable,skillmes)
  local player,room = self.player,self.player.room
  local curcard = room.logic:getCurrentEvent().data[1].card
  if curcard and skillmes and skillmes.targets and type(skillmes.targets) == "table" and #skillmes.targets > 0 then
    local addcards = {amazing_grace=1,god_salvation=1,ljsy=1}
    local seltars = {}
    for _,id in ipairs(skillmes.targets) do
      local tar = room:getPlayerById(id)
      if addcards[curcard.trueName] and not LangAI.ISSAMECAMP(player,tar) then
        table.insert(seltars,id)
      end
      if not addcards[curcard.trueName] and LangAI.ISSAMECAMP(player,tar) then
        table.insert(seltars,id)
      end
    end
    if #seltars > 0 then return EnCodeByUseSkill(skill.name,{},seltars) end
  end
  return ""
end
singleOptiSkill["sheyan"] = function(self,skill,promt,cancelable,skillmes)
  local player,room = self.player,self.player.room
  local curcard = room.logic:getCurrentEvent().data[1].card
  if curcard then
    local seltars = {}
    local specialcard = {duel=true,ex_nihilo=true,fire_attack=true}
    for _,id in ipairs(skillmes.targets) do
      local tar = room:getPlayerById(id)
      if not specialcard[curcard.trueName] then
        if curcard.is_damage_card and LangAI.ISSAMECAMP(player,tar) then table.insert(seltars,tar) end
        if not curcard.is_damage_card and not LangAI.ISSAMECAMP(player,tar) then table.insert(seltars,tar) end
        else
        if curcard.is_damage_card and not LangAI.ISSAMECAMP(player,tar) then table.insert(seltars,tar) end
        if not curcard.is_damage_card and LangAI.ISSAMECAMP(player,tar) then table.insert(seltars,tar) end
      end
    end
    if #seltars > 0 then 
      table.sort(seltars,function(a,b) return a.hp < b.hp end)
      return EnCodeByUseSkill(skill.name,{},{seltars[1].id}) 
    end
  end
  return ""
end
singleOptiSkill["shensu"] = function(self,skill,promt,cancelable,skillmes) 
  local player,room = self.player,self.player.room
  if (string.find(promt,"shensu1") and (player:hasDelayedTrick("indulgence") or #player.player_cards[Player.Hand]< 3)) or (string.find(promt,"shensu3") and player:getMaxCards() >= #player.player_cards[Player.Hand]) then
    local seltars = {}
    for _,pr in ipairs(room:getOtherPlayers(player)) do
      if not LangAI.ISSAMECAMP(player,pr) and not pr:hasSkill("#vine_skill") then
        table.insert(seltars,pr)
      end
    end
    if #seltars > 0 then
      table.sort(seltars,function(a,b) return a.hp < b.hp end)
      seltars = table.map(seltars,Util.IdMapper)
      return EnCodeByUseSkill(skill.name,{},{seltars[1]})
    end
  end
  return ""
end
singleOptiSkill["jieming"] = function(self,skill,promt,cancelable,skillmes)  --界节命优化
  local player,room = self.player,self.player.room
  if skill.name ~= "choose_players_skill" then return "" end
  if skillmes.skillName == "ol_ex__jieming" then
    local friends,enemys = {},{}
    for _,pr in ipairs(room.alive_players) do
      local hands = pr.player_cards[Player.Hand] 
      if LangAI.ISSAMECAMP(player,pr) and (#hands<= pr.maxHp or #hands-pr.maxHp < 3) then table.insert(friends,{pr.id,5-#hands}) end
      if not LangAI.ISSAMECAMP(player,pr) and #hands> pr.maxHp + 2 then table.insert(enemys,{pr.id,#hands-5}) end
    end
    if #friends > 0 then table.sort(friends,function(a,b) return a[2] > b[2] end) end
    if #enemys > 0 then table.sort(enemys,function(a,b) return a[2] > b[2] end) end
    if #friends > 0 and #enemys > 0 then 
      return EnCodeByUseSkill(skill.name,{},friends[1][2] >= enemys[1][2] and {friends[1][1]} or {enemys[1][1]})
    end
    if #friends > 0 then return EnCodeByUseSkill(skill.name,{},{friends[1][1]}) end
    if #enemys > 0 then return EnCodeByUseSkill(skill.name,{},{enemys[1][1]}) end
  else
    if #skillmes.targets == 0 then return "" end
    for _,id in ipairs(skillmes.targets) do
      local tar = room:getPlayerById(id)
      if LangAI.ISSAMECAMP(player,tar) then EnCodeByUseSkill(skill.name,{},{id}) end
    end
  end
  return ""
end
singleOptiSkill["zhengu"] = function(self,skill,promt,cancelable,skillmes)  --镇骨优化
  local player,room = self.player,self.player.room
  local playerhands = player.player_cards[Player.Hand]
  local friends,enemys = {},{}
  for _,pr in ipairs(room:getOtherPlayers(player)) do
    local hands = pr.player_cards[Player.Hand] 
    if LangAI.ISSAMECAMP(player,pr) and #hands <= #playerhands then table.insert(friends,{pr.id,#playerhands-#hands}) end
    if not LangAI.ISSAMECAMP(player,pr) and #hands> #playerhands then table.insert(enemys,{pr.id,#hands-#playerhands}) end
  end
  if #friends > 0 then table.sort(friends,function(a,b) return a[2] > b[2] end) end
  if #enemys > 0 then table.sort(enemys,function(a,b) return a[2] > b[2] end) end
  if #friends > 0 and #enemys > 0 then 
    return EnCodeByUseSkill(skill.name,{},friends[1][2] >= enemys[1][2] and {friends[1][1]} or {enemys[1][1]})
  end
  if #friends > 0 then return EnCodeByUseSkill(skill.name,{},{friends[1][1]}) end
  if #enemys > 0 then return EnCodeByUseSkill(skill.name,{},{enemys[1][1]}) end
  return ""
end
singleOptiSkill["yajiao"] = function(self,skill,promt,cancelable,skillmes)  --涯角优化
  local player,room = self.player,self.player.room
  local secamp = promt == "#yajiao-choose" and LangAI.ISENEMY or LangAI.ISFRIEND
  local tars = LangAI.GetPlayersByCamp(player,skillmes.targets,secamp)
  return #tars > 0 and EnCodeByUseSkill(skill.name,{},{tars[1].id}) or ""
end
singleOptiSkill["yuanyu"] = function(self,skill,promt,cancelable,skillmes)  --怨语优化
  local player,room = self.player,self.player.room
  local tars = {}
  local targets = room:getOtherPlayers(player, false)
  for _, pr in ipairs(targets) do
    local tar = pr
    if not LangAI.ISSAMECAMP(player,tar) and tar:getMark("@@yuanyu") == 0 then
      table.insert(tars,tar)
    end
  end
  if #tars == 0 and #targets > 0 then
    local enemy = table.find(targets,function(pr) return not LangAI.ISSAMECAMP(player,pr) end)
    if enemy then
      table.insert(tars,enemy)
    end
  end
  local hands
  if #tars > 0 then
    hands = player:getCardIds{Player.Hand}
    return EnCodeByUseSkill(skill.name,getSelCardsSeq(hands,1,discards_prio_t),{tars[1].id})
  end
end
singleOptiSkill["bingqing"] = function(self,skill,promt,cancelable,skillmes)  --秉清优化
  local player,room = self.player,self.player.room
  local secamp = promt == "#bingqing-draw" and LangAI.ISFRIEND or LangAI.ISENEMY
  local tars = LangAI.GetPlayersByCamp(player,skillmes.targets,secamp)
  return #tars > 0 and EnCodeByUseSkill(skill.name,{},{tars[1].id}) or ""
end
--------choose_players_skill通用处理（末）----------

--移动牌技能（接口AskForUseActiveSkill）
singleOptiSkill["choose_players_to_move_card_in_board"] = function(self,skill,promt,cancelable,skillmes)
  local player,room = self.player,self.player.room
  local moveflag = skillmes.flag
  if not moveflag or (moveflag and string.find(moveflag,"j")) then
    local friendinfo = prioDismanFriArea(player)
    if friendinfo then
      local enemytar = table.find(room.alive_players,function(pr)
        if not LangAI.ISSAMECAMP(player,pr) and not pr:hasDelayedTrick(friendinfo[2]) then
          return true
        end
      end) 
      if enemytar then
        return EnCodeByUseSkill(skill.name,{},{friendinfo[1],enemytar.id})
      end
    end
  end
  local frilist = {}
  local enylist = {}
  local frinoeplist = {}
  local handleEquipArea = function(who,wholist)  --处理所有玩家的装备区牌
    local euiptypes = table.map(who:getCardIds(Player.Equip),function(eid)
      return Fk:getCardById(eid).sub_type
    end)
    if #euiptypes > 0 then
      local sortbycfg = function(nosort_t,cfg)
        local sort_t = {}
        for _,v in ipairs(cfg) do
          for i,t in ipairs(nosort_t) do
            if v == t then table.insert(sort_t,t) end
          end
        end
        return sort_t
      end
      euiptypes = sortbycfg(euiptypes,MoveEQSeqs) --移动装备的类型进行排序
      table.insert(wholist,{id = who.id,euiptypes = euiptypes})
    end
  end
  for k,pr in ipairs(room.alive_players) do
    if LangAI.ISSAMECAMP(player,pr) then
      handleEquipArea(pr,frilist)
      table.insert(frinoeplist,pr.id)
    else
      handleEquipArea(pr,enylist)
    end
  end
  if #enylist > 0 then
    local selprioenemy = {}  --优先筛选有宝物，+1马，防具，武器的敌人
    local selpriofriend = {}  --优先筛选没有宝物，+1马，防具，武器的队友
    local priotyps = {7,5,4,3}
    for _,pmes in ipairs(enylist) do 
      if table.contains(priotyps,pmes.euiptypes[1]) then
        table.insert(selprioenemy,pmes.id)
      end
    end
    if #frilist == 0 then
      selpriofriend = {table.random(frinoeplist)}
    else
      for _,pmes in ipairs(frilist) do 
        if not table.contains(priotyps,pmes.euiptypes[1]) then
          table.insert(selpriofriend,pmes.id)
        end
      end
      if #selpriofriend == 0 then
        selpriofriend = {table.random(frinoeplist)}
      end
    end  
    local enemypid = #selprioenemy > 0 and selprioenemy[1] or table.random(enylist).id
    local friendpid = selpriofriend[1]
    local selswitchtars = {enemypid,friendpid} --移动顺序是先敌人后队友
    return EnCodeByUseSkill(skill.name,{},selswitchtars)
  else
    return ""
  end
end

-------改判定技能优化（AskForResponseCard）（始）-----------
singleOptiSkill["guicai"] = function(self,skill,promt,cancelable,skillmes) --鬼才（通用改判逻辑）
  local player,room = self.player,self.player.room
  local current = room.logic:getCurrentEvent()
  local data = room.logic:getCurrentEvent().data[1]
  if not data then return "" end
  local tar = data.who
  local reason = data.reason
  local pattern = skillmes.pattern
  if reason and string.find(reason,"luoshen") and table.find(player.player_skills,function(s) if s.trueName == "luoshen" then return true end end) then return "" end 

  local exp = Exppattern:Parse(pattern)
  local avail_cards = table.filter(player:getCardIds{Player.Hand, Player.Equip},function(cid)
    local card = Fk:getCardById(cid)
    if exp:match(card) then return true end
  end)
  if #avail_cards == 0 then return "" end
  local retjson = function(expcids)
    return json.encode{card = expcids[1],targets = {}}
  end
  if Delay_Cards[reason] then
    if reason == "indulgence" then
      if LangAI.ISSAMECAMP(player,tar) and data.card.suit ~= Card.Heart then
        local expcids = patByCards(avail_cards,".|.|heart",1)
        if expcids then return retjson(expcids) end
      end
      if not LangAI.ISSAMECAMP(player,tar) and data.card.suit == Card.Heart then
        local expcids = patByCards(avail_cards,".|.|^heart",1)
        if expcids then return retjson(expcids) end
      end
    elseif reason == "supply_shortage" then
      if LangAI.ISSAMECAMP(player,tar) and data.card.suit ~= Card.Club then
        local expcids = patByCards(avail_cards,".|.|club",1)
        if expcids then return retjson(expcids) end
      end
      if not LangAI.ISSAMECAMP(player,tar) and data.card.suit == Card.Club then
        local expcids = patByCards(avail_cards,".|.|^club",1)
        if expcids then return retjson(expcids) end
      end
    elseif reason == "lightning" then
      if LangAI.ISSAMECAMP(player,tar) and data.card.suit == Card.Spade and data.card.number >= 2 and data.card.number <= 9 then
        local expcids = patByCards(avail_cards,".|.|^spade",1)
        if expcids then return retjson(expcids) end
      end
      if not LangAI.ISSAMECAMP(player,tar) then
        local expcids = patByCards(avail_cards,".|2~9|spade",1)
        if expcids then return retjson(expcids) end
      end
    end
  elseif reason == "#eight_diagram_skill" then
    if LangAI.ISSAMECAMP(player,tar) and data.card.color ~= Card.Red then
      local expcids = patByCards(avail_cards,".|.|heart,diamond",1)
      if expcids then return retjson(expcids) end
    end
    if not LangAI.ISSAMECAMP(player,tar) and data.card.color == Card.Red then
      local expcids = patByCards(avail_cards,".|.|spade,club",1)
      if expcids then return retjson(expcids) end
    end
  else
    local truename = Fk.skills[reason] and Fk.skills[reason].trueName or nil
    if not truename then return "" end
    if truename == "leiji" then
      if LangAI.ISSAMECAMP(player,tar) and data.card.color == Card.Red then
        local expcids = patByCards(avail_cards,".|.|spade",1)
        if expcids then return retjson(expcids) end
        expcids = patByCards(avail_cards,".|.|club",1)
        if expcids then return retjson(expcids) end
      end
      if not LangAI.ISSAMECAMP(player,tar) and data.card.color == Card.Black then
        local expcids = patByCards(avail_cards,".|.|heart,diamond",1)
        if expcids then return retjson(expcids) end
      end
    end
  end
  return ""
end
singleOptiSkill["guidao"] = function(self,skill,promt,cancelable,skillmes) --鬼道
  return singleOptiSkill["guicai"](self,skill,promt,cancelable,skillmes)
end
singleOptiSkill["chenjie"] = function(self,skill,promt,cancelable,skillmes) --臣节
  local player,room = self.player,self.player.room
  local current = room.logic:getCurrentEvent()
  local data = room.logic:getCurrentEvent().data[1]
  if not data then return "" end
  local reason = data.reason
  local pattern = skillmes.pattern

  local exp = Exppattern:Parse(pattern)
  local avail_cards = table.filter(player:getCardIds{Player.Hand, Player.Equip},function(cid)
    local card = Fk:getCardById(cid)
    if exp:match(card) then return true end
  end)
  if #avail_cards == 0 then return "" end
  local retjson = function(expcids)
    return json.encode{card = expcids[1],targets = {}}
  end
  local expcids = patByCards(avail_cards,pattern,1)
  if expcids then return retjson(expcids) end
  return ""
end
-------判定技能优化（AskForResponseCard）（末）-----------

--------dis_sel_cards技能通用处理（始）----------
--自己弃牌或者选牌技能单独优化（原技能discard_skill,choose_cards_skill，接口AskForUseActiveSkill）
singleOptiSkill["dis_sel_cards"] = function(self,skill,promt,cancelable,skillmes) 
  local player,room = self.player,self.player.room
  local hands = skillmes.include_equip and player:getCardIds{Player.Hand, Player.Equip} or player:getCardIds{Player.Hand}
  if skillmes.expand_pile then 
    hands = player:getPile(skillmes.expand_pile)
  end
  if #hands == 0 then return "" end
  if cancelable and LangAI.CANCELSELCARD[skillmes.skillName] then return "" end
  local tskill = Fk.skills[skillmes and skillmes.skillName]
  if tskill and (LangAI.SELENEMYBYCHOOSE[tskill.trueName] or LangAI.SELFRIENDBYCHOOSE[tskill.trueName]) and type(promt) == "string" then  --触发弃牌技能
    local id = getPlayerIdByPromt(promt)
    local target = room:getPlayerById(id)
    if target then
      if LangAI.SELENEMYBYCHOOSE[tskill.trueName] and LangAI.ISSAMECAMP(player,target) then return "" end
      if LangAI.SELFRIENDBYCHOOSE[tskill.trueName] and not LangAI.ISSAMECAMP(player,target) then return "" end
    end
  end
  local discard_t = {}
  local minnum = skillmes.min_num
  local maxnum = skillmes.maxnum
  local num = skillmes.num
  local discard_num = minnum or maxnum or num or 1
  local pattern,exp
  pattern = (skillmes.pattern and skillmes.pattern ~= "") and skillmes.pattern or "."
  exp = Exppattern:Parse(pattern or ".")
  hands = table.filter(hands,function (cid)
    return exp:match(Fk:getCardById(cid))
  end)
  if #hands == 0 then return "" end
  if (maxnum and maxnum >= 99) or (num and num >= 99) then
    discard_num = #hands > 4 and math.floor(math.random(2,3)) or 1
  end
  if #hands <= discard_num then --牌不够全部弃
    if skillmes.skillName == "#axe_skill" and #hands <= discard_num then
      return ""
    end
    return EnCodeByUseSkill(skill.name,hands,{})
  end
  --优化弃牌或者选派逻辑
  discard_t = getSelCardsSeq(hands,discard_num,discards_prio_t)
  return EnCodeByUseSkill(skill.name,discard_t,{})
end
singleOptiSkill["huozhong&"] = function(self,skill)
  local player,room = self.player,self.player.room
  local cantri
  local huozongown
  local sname = "huozhong"
  for _,pr in ipairs(room.alive_players) do
    local skillown = table.find(pr.player_skills,function(s)
      return s.name == sname
    end)
    if skillown and LangAI.ISSAMECAMP(player,pr) then
      cantri = true
      huozongown = pr.id
      break
    end
  end
  if cantri then
    local cardid
    for _,cid in ipairs(player:getCardIds{Player.Hand,Player.Equip}) do
      local card = Fk:getCardById(cid)
      if card.type ~= Card.TypeTrick and card.color == Card.Black then
        cardid = cid
        break
      end
    end
    if cardid then return EnCodeByUseSkill(skill.name,{cardid},{}) end
  end
  return
end
singleOptiSkill["cuijin"] = function(self,skill,promt,cancelable,skillmes)
  local player,room = self.player,self.player.room
  local hands = skillmes.include_equip and player:getCardIds{Player.Hand, Player.Equip} or player:getCardIds{Player.Hand}
  if #hands == 0 then return "" end
  local tskill = Fk.skills[skillmes and skillmes.skillName]
  local id = getPlayerIdByPromt(promt)
  local target = room:getPlayerById(id)
  local toid = room.logic:getCurrentEvent().data[1].tos[1][1]
  local totar = room:getPlayerById(toid)
  if target and totar then
    if LangAI.ISSAMECAMP(player,target) and #totar.player_cards[Player.Hand] < 3 then
      return EnCodeByUseSkill(skill.name,getSelCardsSeq(hands,1,discards_prio_t),{})
    end
    if not LangAI.ISSAMECAMP(player,target) and #totar.player_cards[Player.Hand] > 2 then
      return EnCodeByUseSkill(skill.name,getSelCardsSeq(hands,1,discards_prio_t),{})
    end
  end
  return ""
end
singleOptiSkill["danshou"] = function(self,skill,promt,cancelable,skillmes) --十周年胆守（dis_sel_cards技能里单独优化）
  local player,room = self.player,self.player.room
  local hands = player:getCardIds{Player.Hand, Player.Equip}
  local ds_tar = room:getPlayerById(getPlayerIdByPromt(promt))
  if not ds_tar then return "" end
  if LangAI.ISSAMECAMP(player,ds_tar) then return "" end
  local tarhands = ds_tar.player_cards[Player.Hand]
  if #hands >= #tarhands then
    if #hands < 2 * #tarhands then return "" end
  else
    return ""
  end
end
--------dis_sel_cards技能通用处理（始）----------

--------------技能选项单独优化（始）-----------------
local luochong_selchc
singleOptiSkill["luochong"] = function(self,skill,promt,cancelable,skillmes) --有choose_players也有其他扩展包的luochong需要区分
  local player,room = self.player,self.player.room
  if not skillmes then return end
  if skill.name == "luochong" and skillmes.choice and #skillmes.choice ~= 0 then
    local choice = skillmes.choice
    if luochong_selchc and table.contains(choice,luochong_selchc) then return luochong_selchc end
    luochong_selchc = nil
    return
  end
  if skill.name == "choose_players_skill" and skillmes.skillName =="luochong" and skillmes.targets and #skillmes.targets>0 then
    local selret
    local filtarfunc = function(mark,enemy_friend,condi_func)
      if player:getMark(mark) == "0" then
        local findtar = table.find(room.alive_players,function(pr)
          if enemy_friend =="enemy" and not LangAI.ISSAMECAMP(player,pr) and pr:getMark("luochong-round") == 0 and condi_func(pr) then return true end
          if enemy_friend =="friend" and LangAI.ISSAMECAMP(player,pr) and pr:getMark("luochong-round") == 0 and condi_func(pr) then return true end
        end)
        if findtar then return {findtar.id,mark} end
      end
    end
    selret = filtarfunc("luochong2","enemy",function(pr) return pr.hp < 3 end) or filtarfunc("luochong1","friend",function(pr) return pr:getLostHp() > 0 and pr.hp < 3 end) or filtarfunc("luochong3","enemy",function(pr) return #pr.player_cards[Player.Equip] > 0 end) or filtarfunc("luochong4","friend",function(pr) return true end)
    if not selret then selret = filtarfunc("luochong2","enemy",function(pr) return true end) or filtarfunc("luochong1","friend",function(pr) return true end) or filtarfunc("luochong3","enemy",function(pr) return true end) end 
    if selret then
      luochong_selchc = selret[2]
      return EnCodeByUseSkill(skill.name,{},{selret[1]})
    end
  end
end
local prohiforeach
singleOptiSkill["#puyuanShop-choice"] = function(self,skill,promt,cancelable,skillmes)
  local player,room = self.player,self.player.room
  if not skillmes then return end
  for _,chs in ipairs(skillmes.choice) do
    if chs ~= "Exist" then 
      if prohiforeach and prohiforeach == chs then prohiforeach = nil return "Exist" end
      local pricepos,len = string.find(chs,":%d:") 
      local num
      if not pricepos then 
        local newpos = string.find(chs,"%d")  
        num = tonumber(string.sub(chs,newpos))
      else
        num = tonumber(string.sub(chs,len+1))
      end
      if not num then prohiforeach = nil return "Exist" end
      if player:getMark("@gold_num") >= num then prohiforeach = chs return chs end
    end
  end
  prohiforeach = nil
  return "Exist"
end
singleOptiSkill["yuandi"] = function(self,skill,promt,cancelable,skillmes)
  local player,room = self.player,self.player.room
  if not skillmes then return end
  local choice = skillmes.choice
  if #choice == 1 then return choice[1] end
  local data = room.logic:getCurrentEvent().parent.data[1]
  local tar = data and room:getPlayerById(data.from)
  if not tar then return choice[1] end 
  return LangAI.ISSAMECAMP(player,tar) and "yuandi_draw" or "yuandi_discard"
end
singleOptiSkill["benxi_choice"] = function(self,skill,promt,cancelable,skillmes)
  local player,room = self.player,self.player.room
  if not skillmes then return end
  local choice = skillmes.choice
  local data = room.logic:getCurrentEvent().parent.data[1]
  local usecard = data and data.card
  -- if not usecard then return {"ty_ex__benxi_choice3","ty_ex__benxi_choice4"} end --开发者可能后面会改多选
  if not usecard then return "ty_ex__benxi_choice4" end 
  local selfuse = usecard.skill:feasible({}, {}, player, card)
  if choice and #choice > 0 then
    local others = room:getOtherPlayers(player)
    local emys = LangAI.GetPlayersByCamp(player,others,LangAI.ISENEMY)
    if (usecard.is_damage_card or not selfuse) and #emys > 1 then 
      if table.contains(choice,"ty_ex__benxi_choice1") then return "ty_ex__benxi_choice1" end
      if usecard.is_damage_card and table.contains(choice,"ty_ex__benxi_choice4") then return "ty_ex__benxi_choice4" end
      if not usecard.is_damage_card and table.contains(choice,"ty_ex__benxi_choice3") then return "ty_ex__benxi_choice3" end
    end
    if selfuse and #LangAI.GetPlayersByCamp(player,others,LangAI.ISFRIEND) > 0 then
      if table.contains(choice,"ty_ex__benxi_choice1") then return "ty_ex__benxi_choice1" end
      if table.contains(choice,"ty_ex__benxi_choice3") then return "ty_ex__benxi_choice3" end
    end
    -- if (usecard.is_damage_card or not selfuse) and #emys > 1 then return {"ty_ex__benxi_choice1","ty_ex__benxi_choice4"} end
    -- if selfuse and #LangAI.GetPlayersByCamp(player,others,LangAI.ISFRIEND) > 1 then return {"ty_ex__benxi_choice1","ty_ex__benxi_choice3"} end
    if usecard.trueName == "slash" then 
      local eid = emys[1]:getEquipment(Card.SubtypeArmor)
      local chs2 = table.contains(choice,"ty_ex__benxi_choice2") and "ty_ex__benxi_choice2"
      local chs3 = table.contains(choice,"ty_ex__benxi_choice3") and "ty_ex__benxi_choice3"
      local chs4 = table.contains(choice,"ty_ex__benxi_choice4") and "ty_ex__benxi_choice4"
      local chs34 = chs3 or chs4
      local chs23 = chs2 or chs3
      return (not eid and chs34) and chs34 or (CanPlaySlash(usecard,player,eid) and chs34 or chs23)
      -- local ret = {"ty_ex__benxi_choice3","ty_ex__benxi_choice4"}
      -- return not eid and ret or (CanPlaySlash(usecard,player,eid) and ret or {"ty_ex__benxi_choice2","ty_ex__benxi_choice3"})
    end
    if table.contains(choice,"ty_ex__benxi_choice3") then return "ty_ex__benxi_choice3" end 
    if table.contains(choice,"ty_ex__benxi_choice4") then return "ty_ex__benxi_choice4" end
    -- return {"ty_ex__benxi_choice3","ty_ex__benxi_choice4"} 
  end
end
singleOptiSkill["pianchong"] = function(self,skill,promt,cancelable,skillmes)
  local player,room = self.player,self.player.room
  if not skillmes or not skillmes.choice then return end
  local choice = skillmes.choice
  if #choice == 1 then return choice[1] end
  local redcards,blackcards = 0,0
  for _,cid in ipairs(player.player_cards[Player.Hand]) do
    local card = Fk:getCardById(cid)
    if player:canUse(card) then
      if card.color == Card.Red then redcards = redcards+1 end
      if card.color == Card.Black then blackcards = blackcards+1 end
    end
  end
  return redcards >= blackcards and "red" or "black"
end
singleOptiSkill["shanshen"] = function(self,skill,promt,cancelable,skillmes)
  local player,room = self.player,self.player.room
  if not skillmes then return end
  local choice = skillmes.choice
  if #choice == 1 then return choice[1] end
  --"xianzhu2", "xianzhu3"
  local yuqimark= player:getMark("@yuqi")
  if yuqimark == 0 then yuqimark = {0,3,1,1} end
  local isyuqi1,isyuqi4,isyuqi2 = table.contains(choice,"yuqi1"),table.contains(choice,"yuqi4"),table.contains(choice,"yuqi2")
  if isyuqi1 and yuqimark[1] < 1 then return "yuqi1" end
  if isyuqi1 and (yuqimark[2] > 3 and yuqimark[4] <= yuqimark[2] - 1 ) then return "yuqi1" end
  if isyuqi4 and yuqimark[4] < yuqimark[2] - 1 then return "yuqi4" end
  if isyuqi2 and yuqimark[4] >= yuqimark[4] - 1 then return "yuqi2" end
  if isyuqi1 then return "yuqi1" end
  if table.contains(choice,"yuqi3") then return "yuqi3" end
  return table.random(choice)
end
singleOptiSkill["xianjing"] = function(self,skill,promt,cancelable,skillmes)
  return singleOptiSkill["shanshen"](self,skill,promt,cancelable,skillmes)
end
singleOptiSkill["xianzhu"] = function(self,skill,promt,cancelable,skillmes)
  local player,room = self.player,self.player.room
  if not skillmes or not skillmes.choice then return end
  local choice = skillmes.choice
  if #choice == 1 then return choice[1] end
  --"xianzhu2", "xianzhu3"
  if table.contains(choice,"xianzhu1") then return "xianzhu1" end
  if table.contains(choice,"xianzhu3") and player:getMark("xianzhu3") <= 2 then return "xianzhu3" end
  if table.contains(choice,"xianzhu2") then return "xianzhu2" end
end
singleOptiSkill["yuyun"] = function(self,skill,promt,cancelable,skillmes)
  local player,room = self.player,self.player.room
  if not skillmes then return end
  local choice = skillmes.choice
  local skillName = skillmes.skillName
  if choice then
    if #choice <= 2 and choice[1] == "loseHp" then
      return player.maxHp / 2 < player.hp and "loseHp" or "loseMaxHp"
    end
    -- local selseqs = {"yuyun1", "yuyun2", "yuyun3", "yuyun4", "yuyun5", "Cancel"}
    if table.contains(choice,"yuyun2") then return "yuyun2" end
    if table.contains(choice,"yuyun5") then 
      local tars = LangAI.GetPlayersByCamp(player,room:getOtherPlayers(player, false),LangAI.ISFRIEND)
      if #tars > 0 then 
        table.sort(tars,function(a,b) return #a.player_cards[Player.Hand] < #b.player_cards[Player.Hand] end) 
        if #tars[1].player_cards[Player.Hand] < tars[1].maxHp then self.yuyun5 = tars[1].id return "yuyun5" end
      end 
    end
    if table.contains(choice,"yuyun4") then return "yuyun4" end
    if table.contains(choice,"yuyun1") then return "yuyun1" end
    if table.contains(choice,"yuyun3") then return "yuyun3" end
  end
  if skillName and promt then
    if string.startsWith(promt,"#yuyun2") or string.startsWith(promt,"#yuyun4") then 
      local tars = LangAI.GetPlayersByCamp(player,skillmes.targets,LangAI.ISENEMY)
      if #tars > 0 then table.sort(tars,function(a,b) return a.hp < b.hp end) return EnCodeByUseSkill(skillName,{},{tars[1].id}) end 
    end
    if string.startsWith(promt,"#yuyun5") and self.yuyun5 then 
      local selid = self.yuyun5
      self.yuyun5 = nil
      return EnCodeByUseSkill(skillName,{},{selid})
    end
  end
  return "Cancel"
end
singleOptiSkill["xingchong"] = function(self,skill,promt,cancelable,skillmes) --幸宠
  local player,room = self.player,self.player.room
  if not skillmes or not skillmes.choice then return end
  local choice = skillmes.choice
  if #choice == 1 then return choice[1] end
  local max = 1
  for _,chc in ipairs(choice) do
    local num = tonumber(chc)
    if num > max then
      max = num
    end
  end
  return tostring(max)
end
--------------技能选项单独优化（末）-----------------

--------------唤醒其他技能单独优化（始）-----------------
singleOptiSkill["virtual_viewas"] = function(self,skill) --平襄
  local player,room = self.player,self.player.room
  local tars = table.filter(room:getOtherPlayers(player),function (pr)
    if not LangAI.ISSAMECAMP(player,pr) then return true end
  end)
  if #tars == 0 then return "" end
  table.sort(tars,function(a,b) return a.hp < b.hp end)
  tars = table.map(tars,Util.IdMapper)
  return EnCodeByUseSkill(skill.name,{},{tars[1]})
end
singleOptiSkill["realcard_viewas"] = function(self,skill,promt,cancelable,data) --泛音
  if not data.optional_cards or #data.optional_cards == 0 then return "" end
  local player,room = self.player,self.player.room
  -- if skill.interaction then skill:interaction() end
  local usecard = skill:viewAs(data.optional_cards)
  local seltars = usecard and PlayCards(self,usecard.skill,usecard,true)
  if usecard and usecard.type == Card.TypeEquip and player:getEquipment(usecard.sub_type) then return "" end
  if seltars then return EnCodeByUseSkill(skill.name,data.optional_cards,seltars) end
  return ""
end
singleOptiSkill["suji_viewas"] = function(self,skill) --肃疾
  local player,room = self.player,self.player.room
  local blackcard = table.find(player:getCardIds("he"),function(cid) return Fk:getCardById(cid).color == Card.Black end)
  local seltars = not LangAI.ISSAMECAMP(player,room.current) and {room.current.id} or nil
  if seltars and blackcard then return EnCodeByUseSkill(skill.name,{blackcard},seltars) end
  return ""
end
singleOptiSkill["qinguo_viewas"] = function(self,skill) --勤国
  local player,room = self.player,self.player.room
  if skill.interaction then skill:interaction() end
  local usecard = skill:viewAs()
  local seltars = usecard and PlayCards(self,usecard.skill,usecard,true)
  if seltars then return EnCodeByUseSkill(skill.name,{},seltars) end
  return ""
end
singleOptiSkill["siege_engine_slash"] = function(self,skill) --大公车出牌阶段用杀
  local player,room = self.player,self.player.room
  if skill.interaction then skill:interaction() end
  local usecard = skill:viewAs()
  local seltars = usecard and PlayCards(self,usecard.skill,usecard,true)
  if seltars then return EnCodeByUseSkill(skill.name,{},seltars) end
  return ""
end
singleOptiSkill["zhiyi_viewas"] = function(self,skill) --执义用杀
  local player,room = self.player,self.player.room
  if skill.interaction then skill:interaction() end
  local usecard = skill:viewAs()
  local seltars = usecard and PlayCards(self,usecard.skill,usecard,true)
  if seltars then return EnCodeByUseSkill(skill.name,{},seltars) end
  return ""
end
-- singleOptiSkill["ty_ex__zhuhai_active"] = function(self,skill) --诛害用杀
--   local player,room = self.player,self.player.room
--   if skill.interaction then 
--     self.interaction.data = table.random(skill:interaction())
--   end
--   local usecard = skill:viewAs()
--   local seltars = usecard and PlayCards(self,usecard.skill,usecard,true)
--   if seltars then return EnCodeByUseSkill(skill.name,{},seltars) end
--   return ""
-- end
singleOptiSkill["chouce"] = function(self,skill,promt,cancelable,skillmes) --筹策
  local player,room = self.player,self.player.room
  local prompt = promt
  local t
  if prompt == "#chouce-draw" then
    t = player:getMark("xianfu")
    t = (type(t) == "table" and t[1] and t[1][1] and LangAI.ISSAMECAMP(player,room:getPlayerById(t[1][1]))) and {t[1][1]} or {player.id}
  else
    t = prioDismanFriArea(player)
    if t then
      self.disFriendCard = t[3]
      t = {t[1]}
    else
      local findtar = table.find(room.alive_players,function(pr)
        if not LangAI.ISSAMECAMP(player,pr) then
          return true
        end
      end)
      t = findtar and {findtar.id} or nil
    end
    -- local findtar = table.find(room.alive_players,function(pr)
    --   if not LangAI.ISSAMECAMP(player,pr) then
    --     return true
    --   end
    -- end)
    -- t = findtar and {findtar.id} or nil
  end
  if t then return EnCodeByUseSkill(skill.name,{},t) end
  return ""
end
--十周年 周不疑
singleOptiSkill["shijiz_viewas"] = function(self,skill) -- 十周年 周不疑 十计
  local player,room = self.player,self.player.room 
  local hands = player:getCardIds(Player.Hand)
  if #hands == 0 then return "" end
  local cardName = player:getMark("shijiz-tmp")
  local usecard = skill:viewAs(cardName)
  local seltars = usecard and PlayCards(self,usecard.skill,usecard,true)
  if not seltars then return "" end
  if seltars and type(seltars) == "string" and string.find(seltars, "\\\"recast\\\"") then return "" end
  return EnCodeByUseSkill(skill.name,getSelCardsSeq(hands,1,discards_prio_t),seltars) 
end
singleOptiSkill["silun_active"] = function(self,skill,mes) -- 十周年 周不疑 四论
  local player,room = self.player,self.player.room  
  local interactionData
  local hands = table.clone(player:getCardIds("h"))
  local equips = table.clone(player:getCardIds("e"))
  local he = table.connect(hands,equips)
  local card
  --牌堆顶
  interactionData = "Top"
  local judges
  local isFriend --是否友善控顶
  --检测是否为准备阶段
  if player.phase == Player.Start then 
    judges = table.clone(player:getCardIds("j")) 
    isFriend = true
  else
    --获取当前回合玩家的下家
    local nextPr = room.current:getNextAlive()
    for i = 1, #room.alive_players do
      if nextPr.faceUp then break end
      nextPr = nextPr:getNextAlive()
    end
    judges = table.clone(nextPr:getCardIds("j"))
    if #judges > 0 then
      isFriend = LangAI.ISSAMECAMP(player,nextPr)
    end
  end
  --检测判定区
  if judges and #judges > 0 then
    local max_num = math.min(4,#judges)
    local num =  getPlayerIdByPromt(mes)
    if #judges >= num then
      local c = Fk:getCardById(judges[num])
      if c.trueName == "indulgence" then
        card = getSelCardsSeq(table.filter(he,function(cid) return isFriend == (Fk:getCardById(cid).suit == Card.Heart) end),1,discards_prio_t)[1]
      elseif c.trueName == "supply_shortage" then
        card = getSelCardsSeq(table.filter(he,function(cid) return isFriend == (Fk:getCardById(cid).suit == Card.Club) end),1,discards_prio_t)[1]
      elseif c.trueName == "lightning" then
        card = getSelCardsSeq(table.filter(he,function(cid) return isFriend == (not (Fk:getCardById(cid).suit == Card.Spade and Fk:getCardById(cid).number <= 9 and Fk:getCardById(cid).number >= 2)) end),1,discards_prio_t)[1]
      end
      if not card then
        if #hands > 0 then
          card = getSelCardsSeq(hands,1,discards_prio_t)[1]
        else
          card = getSelCardsSeq(he,1,discards_prio_t)[1]
        end
      end
      return EnCodeByUseSkill(skill.name,{card},nil,interactionData) 
    end
  end
  --寻找可获得装备的队友或自己
  local tars = table.filter(room:getAlivePlayers(),function (pr)
    return LangAI.ISSAMECAMP(player,pr) and 
      #table.filter(ImporEeuipsType,function (type_name) return not pr:getEquipment(type_name) end) > 0
    end)
  --场上
  interactionData = "Field"
  --1.上装备
  --寻找可移动的装备牌
  local cards = table.filter(he,function(cid) return Fk:getCardById(cid).type == Card.TypeEquip end)
  local card
  local tar
  if #cards > 0 then
    --寻找可复原的队友或自己
    local tarsNeed = table.filter(tars,function(pr) return not pr.faceup end)
    --不可复原的加在队列末位
    tarsNeed = table.connectIfNeed(tarsNeed,tars)
    for _, p in ipairs(tarsNeed) do
      p = tarsNeed[1]
      --寻找其可以使用的装备牌
      card = table.find(cards,function(cid)
        return not p:getEquipment(Fk:getCardById(cid).sub_type)
      end)
      if card then
        tar = p.id
        break
      end
    end
  end
  --可上装备
  if tar and card then 
    return EnCodeByUseSkill(skill.name,{card},{tar},interactionData) 
  end
  --2.上兵乐
  --寻找判定区未废除的敌人
  local tars = table.filter(room:getOtherPlayers(player),function (pr)
    return not LangAI.ISSAMECAMP(player,pr) and not table.contains(pr.sealedSlots, Player.JudgeSlot)
  end)
  local card
  local tar
  --寻找兵、乐/延时锦囊
  local cards = table.filter(hands,function(cid) return Fk:getCardById(cid).sub_type == Card.SubtypeDelayedTrick end)
  for _, cid in ipairs(cards) do
    local c = Fk:getCardById(cid)
    --寻找可兵乐的敌人
    local tarsNeed = table.filter(tars,function(pr) return not pr:hasDelayedTrick(c.trueName) end)
    if #tarsNeed > 0 then
      if c.trueName == "indulgence" then
        table.sort(tarsNeed,function (a,b) return (#a:getCardIds("h") - a:getMaxCards()) > (#b:getCardIds("h") - b:getMaxCards()) end)
      elseif c.trueName == "supply_shortage" then
        table.sort(tarsNeed,function (a,b) return #a:getCardIds("h") < #b:getCardIds("h") end)
      else
        table.sort(tarsNeed,function (a,b) return a.hp < b.hp end)
      end
      tar = tarsNeed[1].id
      card = cid
      break
    end
  end
  --可兵乐
  if tar and card then 
    return EnCodeByUseSkill(skill.name,{card},{tar},interactionData) 
  end
  --牌堆底
  interactionData = "Bottom"
  local selcard = getSelCardsSeq(hands,1,discards_prio_t)
  if #hands > 0 then
    selcard = getSelCardsSeq(hands,1,discards_prio_t)
  else
    selcard = getSelCardsSeq(he,1,discards_prio_t)
  end
  return EnCodeByUseSkill(skill.name,selcard,nil,interactionData) 
end
singleOptiSkill["aocai"] = function(self,skill,promt,cancelable,skillmes)--傲才
  local player,room = self.player,self.player.room
  local hands = player.special_cards["aocai"] 
  if #hands == 0 then return end
  local cid = table.find(hands,function(cid)
    local c = Fk:getCardById(cid)
    return not player:prohibitUse(c)
  end)
  local setars = skillmes.must_targets or (skillmes.exclusive_targets and skillmes.exclusive_targets[1] and {skillmes.exclusive_targets[1]}) or {}
  if cid then return EnCodeByUseSkill(skill.name,{cid},setars) end
  return
end
--
--------------唤醒其他技能单独优化（末）-----------------

--发动其他技能
local useSkillNames = {discard_skill = true,choose_cards_skill = true,distribution_skill=true}
random_cb.AskForUseActiveSkill = function(self, jsonData)
  local player = self.player
  local room = player.room
  if not jsonData then return end
  local data = json.decode(jsonData)
  local skill = Fk.skills[data[1]]
  local promt = data[2]
  local cancelable = data[3]
  local skillmes = data[4]
  if (skill and LangAI.BLACKSKILLS[skill.trueName]) or (skillmes and LangAI.BLACKSKILLS[skillmes.skillName]) then
    return ""
  end
  if cancelable and LangAI.CANCELSELCARD[data[1]] then
    return ""
  end
  if skillmes and promt and string.find(promt,"#askForPindian") then --优先优化拼点
    return singleOptiSkill["askforPinDian"](self,skill,promt,cancelable,skillmes)
  end
  if skill and useSkillNames[skill.trueName] and skillmes then --选择或弃自己牌的技能另外作处理askforcard
    local skilltrue = skillmes and skillmes.skillName and Fk.skills[skillmes.skillName] and Fk.skills[skillmes.skillName].trueName
    local skillfunc = singleOptiSkill[skilltrue]
    local result = skillfunc and skillfunc(self,skill,promt,cancelable,skillmes) or nil --单独优化其他技能discard_skill/choose_cards_skill
    if result then return result end
    return singleOptiSkill["dis_sel_cards"](self,skill,promt,cancelable,skillmes)  --没有的再用discard_skill/choose_cards_skill
  end
  if skill then 
    if skill.trueName == "choose_players_skill" then --选择其他角色技能另外作处理
      local skilltrue = skillmes and skillmes.skillName and Fk.skills[skillmes.skillName] and Fk.skills[skillmes.skillName].trueName
      local skillfunc = singleOptiSkill[skilltrue]
      local result = skillfunc and skillfunc(self,skill,promt,cancelable,skillmes) or nil --单独优化其他技能chooseplayers
      if result then return result end
      local ret = singleOptiSkill[skill.trueName](self,skill,promt,cancelable,skillmes)  --没有的再用chooseplayers
      if ret then return ret end
    else
      local skillfunc = singleOptiSkill[skill.trueName] --使用其他技能。比如勤国，平襄，筹测内嵌的其他技能
      return skillfunc and skillfunc(self,skill,promt,cancelable,skillmes)
    end
  end
  if not skill.feasible then return "" end
  for k, v in pairs(skillmes) do
    skill[k] = v
  end
  local ret = useActiveSkill(self, skill)
  if ret then return ret end
  return ""
end

--对选项内容进行处理
local filterChoices = function(choice,selcont)
  return table.find(choice,function(content) 
    if string.find(content,selcont) then 
      return true 
    end 
  end)
end
--选项功能
random_cb.AskForChoice = function(self, jsonData)
  --改为随机选项
  local player = self.player
  local room = player.room
  local data = json.decode(jsonData)
  -- p(data)
  local choice = data[1]
  local skillname = data[3]
  local skill = Fk.skills[skillname]
  if skill and LangAI.BLACKSKILLS[skill.trueName] then
    return ""
  end
  if type(choice) == "table" and #choice > 0 then
    if skillname == "#puyuanShop-choice" then
      local ret= singleOptiSkill["#puyuanShop-choice"](self,skill,nil,nil,{choice = choice})
      if ret then return ret end
    end
    if skill and singleOptiSkill[skill.trueName] then
      local ret= singleOptiSkill[skill.trueName](self,skill,nil,nil,{choice = choice})
      if ret then return ret end
    end
    if skillname and type(skillname) == "string" and skill and LangAI.SKILLCHOICE[skill.name] then
      local tarmes = data[4]
      local tarcont = LangAI.SKILLCHOICE[skill.name]
      if tarcont.mustchose then
        local chc = filterChoices(choice,tarcont.mustchose)
        if chc then return chc end
      end
      local id = getPlayerIdByPromt(tarmes)
      if #tarmes == 0 or not id then id = room.current.id end
      local target = room:getPlayerById(id)
      if target then
        if tarcont.tar == "friend" then
          if LangAI.ISSAMECAMP(player,target) then
            local chc = filterChoices(choice,tarcont.chose)
            if chc then return chc end
          end
        elseif tarcont.tar == "enemy" then
          if not LangAI.ISSAMECAMP(player,target) then
            local chc = filterChoices(choice,tarcont.chose)
            if chc then return chc end
          end
        else
          if LangAI.ISSAMECAMP(player,target) then
            if tarcont.chose.friend then
              local chc = filterChoices(choice,tarcont.chose.friend)
              if chc then return chc end
            end
          else
            if tarcont.chose.enemy then
              local chc = filterChoices(choice,tarcont.chose.enemy)
              if chc then return chc end
            end
          end
        end
      end
    end
    local randi = math.floor(math.random(1,#choice)+0.5) 
    local rand = choice[randi]
    return rand and rand or ""
  end
  return ""
end

local invokeBySpec = {}
invokeBySpec["zhenlie"] = function (player) --贞烈
  local room = player.room
  local data = room.logic:getCurrentEvent().data
  if not data[1] or not data[1].card then return "" end
  data = data[1]
  local from = data.from
  local tar = room:getPlayerById(from)
  if not tar then return "" end
  if LangAI.ISSAMECAMP(player,tar) then return "" end
  if player.hp > 1 then 
    if data.card.is_damage_card then return "1" end
    if data.card:isCommonTrick() and not data.card.multiple_targets and player.hp > 2 then return "1" end
  else
    if data.card.is_damage_card then
      local peach_anales = table.filter(player.player_cards[Player.Hand],function(cid)
        local card = Fk:getCardById(cid)
        if card.trueName == "peach" or card.trueName == "analeptic" then return true end
      end)
      if #peach_anales > 0 or #player.player_cards[Player.Hand] == 0 then return "1" end
      local carddeals = {"jink","slash;jink;nullification"}
      if carddeals[data.card.type] then
        local pattern = carddeals[data.card.type]
        local exp = Exppattern:Parse(pattern)
        local respond = table.find(player.player_cards[Player.Hand],function(cid)
          local card = Fk:getCardById(cid)
          if exp:match(card) then return true end
        end)
        return respond and "" or "1"
      end
    end
  end
  return "1"
end
invokeBySpec["l_kuixi"] = function (player) --窥喜
  local room = player.room
  if #player.player_cards[Player.Hand] < 4 then return "1" end
  return ""
end
invokeBySpec["danshou"] = function (player,data) --十周年界胆守
  local room = player.room
  local mes = data[2]
  local id =  getPlayerIdByPromt(mes)
  local target = room:getPlayerById(id)
  if not target then return "1" end
  local tarhands = #target.player_cards[Player.Hand]
  local playerhands = #player.player_cards[Player.Hand]
  if string.match(mes,"draw") then --摸牌
    if LangAI.ISSAMECAMP(player,target) then
      return "1"
    else
      if tarhands > 2 and playerhands < 3 then
        return "1"
      end
      if tarhands < 2 and playerhands > 0 then
        return ""
      end
      if playerhands >= tarhands then
        if playerhands >= 2 * tarhands then 
          return ""
        else
          return "1"
        end
      else
        return "1"
      end
    end
  else  --0牌直伤害
    if LangAI.ISSAMECAMP(player,target) then
      return ""
    else
      return "1"
    end
  end
end
invokeBySpec["#ice_sword_skill"] = function (player) --寒冰剑
  local room = player.room
  local current = room.logic:getCurrentEvent()
  local e = current:findParent(GameEvent.CardEffect,Self)
  if not e then return "" end
  local cardeff = e.data and e.data[1] or nil
  if not cardeff then return "" end
  local target = room:getPlayerById(cardeff.to)
  if target:getEquipment(Card.SubtypeTreasure) or target:getEquipment(Card.SubtypeArmor) then
    return "1"
  else
    if target:getEquipment(Card.SubtypeDefensiveRide) and player:distanceTo(target) ~= 1 then
      return "1"
    else
      return ""
    end
  end
end
invokeBySpec["fenli"] = function (player,data) --奋厉
  local mes = data[2]
  if mes then
    if string.find(mes,"phase_draw") then
      return ""
    end 
    if string.find(mes,"phase_play") then
      if #player.player_cards[Player.Hand] < 4 then
        return "1"
      else
        return ""
      end
    end
    if string.find(mes,"phase_discard") then
      return "1"
    end 
  end
  return ""
end

function LangAI:friFoeByCard(skilltar,isjudge,sendata)
  local player = self.player
  local room = player.room
  local current = room.logic:getCurrentEvent()
  -- local e = current:findParent(GameEvent.CardEffect,Self)
  if not current.data or #current.data == 0 then return "" end
  -- local cardeff = e.data and e.data[1] or nil
  local data = current.data[1]
  local evevntype = current.event
  local target,restarget
  if type(data) == "function" then
    return "1"
  end
  if data then
    if data.to then --一般是受到伤害时候
      target = type(data.to) == "number" and room:getPlayerById(data.to) or data.to 
    elseif data.who then
      target = type(data.who) == "number" and room:getPlayerById(data.who) or data.who
    end
  end
  if not target and sendata and type(sendata) == "table" and sendata[2] and type(sendata[2]) == "string" then
    target = room:getPlayerById(getPlayerIdByPromt(sendata[2]))
  end
  if not target and data.tos and #data.tos > 0 then  --一般是即将成为目标时候
    -- local tids = AimGroup:getAllTargets(data.tos)
    local tids = data.tos
    if #tids == 1 then
      target = room:getPlayerById(tids[1][1])
    else
      if isjudge then
        local tid = table.find(tids,function (pid)
          if pid[1] == player.id then
            return true
          end
        end)
        if tid then
          target = room:getPlayerById(tid[1])
        end
      end
    end
  end
  if not target then return "" end
  if isjudge and data.from then
    restarget = type(data.from) == "number" and room:getPlayerById(data.from) or data.from
  end
  if LangAI.ISSAMECAMP(player,target) and skilltar == "friend" then 
    if isjudge and restarget and not restarget.dead then
      if LangAI.ISSAMECAMP(player,restarget) then
        return ""
      else
        return "1"
      end
    end
    return "1"
  end
  if not LangAI.ISSAMECAMP(player,target) and skilltar == "enemy" then
    return "1"
  end
  return ""
end

function LangAI:invokeSkillByType(typemes,name,data)
  local type = typemes.type
  local skilltar = typemes.skilltar
  local isjudege = typemes.isjudge
  if type == LangAI.INVOKENORMAL then
    return self:friFoeByCard(skilltar,isjudege,data)
  elseif type == LangAI.INVOKESPECIAL then
    local handle = invokeBySpec[name]
    if handle then
      return handle(self.player,data)
    else
      return ""
    end
  end
  return ""
end

function LangAI:invokeSkill(name,data)
  local typemes = LangAI.INVOKESKILL[name]
  if typemes then
    local result = self:invokeSkillByType(typemes,name,data)
    return result
  else
    return "1"
  end
end

--询问技能发动
random_cb.AskForSkillInvoke = function(self, jsonData)
  local data=jsonData
  if type(jsonData)=="string" then
    data = json.decode(jsonData)
  end
  local skill = Fk.skills[data[1]]
  if skill and LangAI.BLACKSKILLS[skill.trueName] then
    return ""
  end
  local invoFunc = skill and self:invokeSkill(skill.trueName,data) or ""
  return invoFunc
end

local handleEncode = function (data,isview)
  if isview then
    return json.encode{
      card = json.encode{
        skill = data.skillname,
        subcards = data.selected_cards,
      },
      targets = data.targets and data.targets or {},
      interaction_data = data.interaction_data and data.interaction_data or nil
    }
  end
  return json.encode{card = data.card,targets = data.targets and data.targets or {}} 
end

local nulliwhite_t = {ex_nihilo=true,god_salvation=true,amazing_grace=true,ljsy=true}
local damageCards = {savage_assault = true,archery_attack=true,duel=true,fire_attack=true}
--使用桃
local askforPeachHandle = function (usemes,card,player,isviewas)
  local room = player.room
  if string.find(usemes,"#AskForPeaches:") then
    local one = string.find(usemes,":",1)
    local last =  string.find(usemes,":",one+1)
    local id = string.sub(usemes,one+1,last-1)
    local idnumber = tonumber(id)
    local tar = room:getPlayerById(idnumber)
    if tar and not LangAI.ISSAMECAMP(player,tar) then
      return ""
    else
      local data = not isviewas and {card = card} or card
      return handleEncode(data,isviewas)
    end
  elseif string.find(usemes,"#AskForPeachesSelf") then
    local data = not isviewas and {card = card} or card
    return handleEncode(data,isviewas)
  end
end
local getNulliTar = function(nulli,usemes)
  local one,over = string.find(usemes,nulli)
  if one and over then
    local last = string.find(usemes,":",over+1)
    local id = string.sub(usemes,over+1,last-1)
    local trick = string.sub(usemes,last+1)
    id = tonumber(id)
    local name_splited = trick:split("__")
    trick = name_splited[#name_splited]
    return id,trick
  end
end
--使用无懈可击
local askforNulliHandle = function (target,trick_card,card,num,player,isviewas)
  local room = player.room
  local trick,tar = trick_card,target
  local hands,judeges = player.player_cards[Player.Hand],player.player_cards[Player.Judge]
  local nullinum,isindul = num,false
  if #judeges > 0 then
    for _, id in ipairs(judeges) do
      local c = player:getVirualEquip(id)
      if not c then c = Fk:getCardById(id) end
      if c.trueName == "indulgence" then
        isindul = true
      end
    end
    if nullinum <= 2 and isindul then  --少于3个无懈且被乐了会优先保留
      if room.current.id ~= player.id then 
        return ""
      else
        if trick == "lightning" then return "" end
        if isindul and trick ~= "indulgence" and nullinum == 1 then --对于判定区多个锦囊牌且只有1个无邪则只对乐无邪
          return ""
        end
        local data = not isviewas and {card = card} or card
        return handleEncode(data,isviewas)
      end
    end
  end
  if nulliwhite_t[trick] then  --对自己或者队友使用增益的卡牌不打无懈
    if LangAI.ISSAMECAMP(player,tar) then
      return ""
    else
      local data = not isviewas and {card = card} or card
      return handleEncode(data,isviewas)
    end
  else
    if LangAI.ISSAMECAMP(player,tar) then  --对自己或者队友伤害锦囊打无懈看情况
      if damageCards[trick] and tar.hp > 2 and nullinum < 3 then
        return ""
      else
        if trick == "lightning" then return "" end
        local data = not isviewas and {card = card} or card
        return handleEncode(data,isviewas)
      end
    end
  end
  return ""
end
--反打无懈可击
local askforToNulliHandle = function (target,trick_card,card,player,isviewas)
  -- local trick = trick_card
  --不无懈自己或者队友
  if LangAI.ISSAMECAMP(player,target) then
    return ""
  else
    local data = not isviewas and {card = card} or card
    return handleEncode(data,isviewas)
  end
end
--回合外使用或响应卡牌效果
local askforCommonHandle = function (mustars,player,card_name,card,avalicard,filtercards)
  local tar,armor
  local room = player.room
  if mustars then
    tar = room:getPlayerById(mustars[1])
    if not tar then return filtercards end
    armor = tar:getEquipment(Card.SubtypeArmor)
  end
  if tar then
    if not LangAI.ISSAMECAMP(player,tar) then
      if card_name == "slash" then  --使用杀判断对面防具
        if not armor then
          if #filtercards == 0 then table.insert(filtercards,card) end
        else
          local canplay = CanPlaySlash(avalicard,player,armor)
          if canplay then
            if #filtercards == 0 then table.insert(filtercards,card) end
          end
        end
      else
        if #filtercards == 0 then table.insert(filtercards,card) end  --使用其他牌响应
      end
    end
  else
    if #filtercards == 0 then table.insert(filtercards,card) end  --使用其他牌响应
  end
  return filtercards
end
--询问使用卡牌
random_cb.AskForUseCard = function(self, jsonData)
  local player,room = self.player,self.player.room
  local data = json.decode(jsonData)
  local card_name = data[1]
  local pattern = data[2] or card_name
  local usemes = data[3]
  local cancelable = data[4] or true
  local mes = data[5]

  local current = room.logic:getCurrentEvent()
  local use_data = current.data[1]
  local use_card_from,use_card,damage = nil,nil,1
  if use_data and type(use_data) == "table" then
    use_card = use_data.card
    use_card_from = use_data.from
    damage = use_data.additionalDamage and use_data.additionalDamage + 1 or 1
  end
  if use_card and use_card.is_damage_card then
    local dmgskill = table.find(player.player_skills,function(s) return LangAI.DAMAGESKILLS[s.trueName] end) --检测是不是卖血技能
    local invalskill = player:getMark(MarkEnum.UncompulsoryInvalidity.."-turn")
    if dmgskill and invalskill == 0 and (pattern=="jink" or pattern=="nullification") and LangAI.CellBlood(player,damage) then
      if pattern=="nullification" and string.startsWith(usemes,"#AskForNullification") then
        -- if use_card and use_card.is_damage_card then
          local nullitarid = getNulliTar("#AskForNullification::",usemes)
          if nullitarid and nullitarid == player.id then return "" end
        -- end
      else
        return ""
      end
    end
  end
  local nullitotar,nillibytrick
  if pattern == "nullification" then --使用或者反打无懈提取无懈对象和无懈的锦囊
    local nullikey = string.startsWith(usemes,"#AskForNullification:") and "#AskForNullification::" or "#AskForNullificationWithoutTo:"
    nullitotar,nillibytrick = getNulliTar(nullikey,usemes)
    nullitotar = room:getPlayerById(nullitotar)
    use_card_from = room:getPlayerById(use_card_from)
    if use_card_from and LangAI.ISSAMECAMP(player,use_card_from) and nullitotar and LangAI.ISSAMECAMP(player,nullitotar) then return "" end
  end

  local exp = Exppattern:Parse(pattern)
  self:UpFilterSkills()
  --询问时候检测筛选出使用的卡
  local avail_cards = table.filter(player:getCardIds("he"), function(id)
    local card = Fk:getCardById(id,true)
    card = CardFilterHandle(player,card,self.fiterskills)
    return exp:match(card) and not player:prohibitUse(card)
  end)
  --没有使用的卡检测主动视为技能and s.pattern and type(s.pattern) == "string" and string.find(s.pattern,pattern)
  local hasvs
  if #avail_cards == 0 then
    local vss = table.find(player.player_skills, function(s)
      if s:isInstanceOf(ViewAsSkill) and type(s.pattern) == "string" and #s.pattern > 0 and s.name ~= "spear_skill" then
        local patret = exp:matchExp(s.pattern)
        if patret then return (s.enabledAtPlay and s:enabledAtPlay(player)) or (s.enabledAtResponse and s:enabledAtResponse(player)) end
      end
    end)
    --主动视为技能看看是否有满足条件卡牌加入使用卡组
    if vss then
      local ret = useVSSkill(self, vss, nil,card_name)
      if ret then table.insert(avail_cards,ret) hasvs = true end
    end
  end
  if pattern == "jink" then --检测敌人有没有无双，浪无双，这种需要连续出多闪的技能
    local from = use_card and use_card.trueName == "slash" and use_card_from and room:getPlayerById(use_card_from)
    local wushuangs = {wushuang=2,l_wushuang=3}
    local wushuang = from and table.find(from.player_skills,function(s)
      if wushuangs[s.trueName] then return true end
    end)
    if wushuang and use_data and use_data.fixedResponseTimes and use_data.fixedResponseTimes.jink then
      self.usejinknum = self.usejinknum or use_data.fixedResponseTimes.jink
      if #avail_cards < self.usejinknum and not player:hasSkill("#eight_diagram_skill") and not hasvs then return "" end
      self.usejinknum = self.usejinknum - 1
      if self.usejinknum <= 0 then self.usejinknum = nil end
    end
  end
  if #avail_cards > 0 then
    local filtercards = {}
    local mustars = mes and mes.must_targets or mes.exclusive_targets
    local isviewas = false
    for _, card in ipairs(avail_cards) do
      if type(usemes) ~= "string" then break end
      local avalicard = card
      if type(card) == "number" then
        avalicard = Fk:getCardById(card)
      else
        isviewas = true
      end
      if avalicard.trueName == "nullification" then
        if string.startsWith(usemes,"#AskForNullification:") then
          return askforNulliHandle(nullitotar,nillibytrick,card,#avail_cards,player,isviewas)  --使用无懈可击
        elseif string.startsWith(usemes,"#AskForNullificationWithoutTo:") then
          return askforToNulliHandle(nullitotar,nillibytrick,card,player,isviewas)  --反打无懈可击
        end
      end
      if card_name == "peach" then
        return askforPeachHandle(usemes,card,player,isviewas)  --使用酒桃
      end
      -- if card_name == avalicard.trueName then  --通用使用卡牌以及卡牌指向目标
        filtercards = askforCommonHandle(mustars,player,card_name,card,avalicard,filtercards)
      -- end
    end
    if #filtercards > 0 then
      local data 
      if not isviewas then
        data = {card = filtercards[1],targets = mustars or {}}
      else
        if mustars then
          filtercards[1].targets = mustars
        end
        data = filtercards[1]
      end
      return handleEncode(data,isviewas)
    end
  end
  return ""
end

---@param self LangAI
---响应打出卡牌
local RespSlashNum
random_cb.AskForResponseCard = function(self, jsonData)
  local player = self.player
  local room = self.room
  local data = json.decode(jsonData)
  local skill = Fk.skills[data[1]]
  local pattern = data[2]
  local promt = data[3]
  local cancelable = data[4]
  local selected_targets

  if skill and LangAI.BLACKSKILLS[skill.trueName] then
    return ""
  end
  if skill and singleOptiSkill[skill.trueName] then
    local ret = singleOptiSkill[skill.trueName](self,skill,promt,nil,{pattern=pattern})
    return ret
  end
  local current = room.logic:getCurrentEvent()
  local cardskill = current.data and current.data[3]
  if cardskill and cardskill.name == "duel_skill" and player.hp ~= 1 and current.data[2] and #current.data[2].player_cards[Player.Hand] > #player.player_cards[Player.Hand] + 2 then
    return ""
  end
  --检测是不是卖血技能
  local dmgskill = table.find(player.player_skills,function(s)
    return LangAI.DAMAGESKILLS[s.trueName]
  end)
  local invalskill = player:getMark(MarkEnum.UncompulsoryInvalidity.."-turn")
  if dmgskill and invalskill == 0 and LangAI.CellBlood(player,1) then
    return ""
  end
  --检测无双
  local from = cardskill and cardskill.name == "duel_skill" and current.data[2]
  local wushuangs = {wushuang=2,l_wushuang=3}
  local wushuang = from and table.find(from.player_skills,function(s)
    if wushuangs[s.trueName] then return true end
  end)
  if wushuang and pattern == "slash" then
    local parent = current.parent
    local parentdata = parent.data[1]
    if parentdata.fixedResponseTimes then
      if not RespSlashNum then
        if #table.filter(player.player_cards[Player.Hand],function(cid)
          if Fk:getCardById(cid).trueName == "slash" then return true end
        end) < parentdata.fixedResponseTimes.slash then return "" end
        RespSlashNum = (RespSlashNum or 0) + 1
      else
        RespSlashNum = RespSlashNum + 1
        if RespSlashNum == parentdata.fixedResponseTimes.slash then
          RespSlashNum = nil
        end
      end
    end
  end
  local exp = Exppattern:Parse(pattern)
  local avail_cards = table.filter(player:getCardIds{ Player.Hand, Player.Equip }, function(id)
    local card = Fk:getCardById(id)
    return exp:match(card) and not player:prohibitResponse(card)
  end)
  if #avail_cards > 0 then
    return json.encode{
    card = table.random(avail_cards),
    targets = {},
  } end
  -- TODO: vs skill
  return ""
end
--使用卡牌顺序(player:getMark("df_fengkuang") ~= 0)
local upUseCardsSeq = function (self,cpos,raslash)
  local player,room,drank,hands = self.player,self.player.room,self.player.drank,self.handcards
  local slashlist,analeplist = {},{}
  self.use_analep = nil
  for j = 1, #hands do --先打装备，锦囊牌
    local card = hands[j]
    local id = card.id
    if card.type == Card.TypeBasic and not self.jumpcards[card.name] then
      if card.trueName == "analeptic" then table.insert(analeplist,id) end
      if card.trueName == "slash" then table.insert(slashlist,card) end
      if card.trueName == "peach" then return card end
    end
    if card.type == Card.TypeEquip then
      local eid = player:getEquipment(card.sub_type)
      if not eid then
        if canUseEquip(player,card) then --
          if card.sub_type == Card.SubtypeWeapon and UsePrioWeaponSeq[card.trueName] then
            local suitweapon = getPrioWeapon(self)
            return suitweapon and suitweapon[2] or card
          else
            return card
          end
        end
      else
        local equipcard = Fk:getCardById(eid)
        if equipcard.trueName == "silver_lion" and canUseEquip(player,card) then
          return card
        end
        if equipcard.sub_type == Card.SubtypeWeapon and UsePrioWeaponSeq[equipcard.trueName] then
          local suitweapon = getPrioWeapon(self)
          if suitweapon and UsePrioWeaponSeq[equipcard.trueName] > suitweapon[1] then
            return suitweapon[2]
          end
        end
        if self.repequip then
          if equipcard.sub_type == Card.SubtypeWeapon then
            if UsePrioWeaponSeq[equipcard.trueName] then return card end
          else
            return card
          end  
        end 
      end
    end
    if card.type == Card.TypeTrick and UseRecordCards[card.trueName] and not self.jumpcards[card.name] then return card end  --优先用不卡手锦囊最后用装备基本牌策略
  end
  --酒杀策略（等到最后一张杀时候喝酒）
  if #slashlist > 0 and #analeplist > 0 and drank == 0 then
    if raslash == 1 or #slashlist == 1 then
      self.use_analep = table.random(analeplist)
    end
  end
  --出杀策略（优先使用火，雷,红色的杀）
  if #slashlist > 0 then
    if #slashlist == 1 then
      return slashlist[1]
    else
      for _,card in ipairs(slashlist) do
        if card.name == "fire__slash" or card.name == "thunder__slash" or card.color == Card.Red then
          return card
        end
      end
      return table.random(slashlist)
    end
  end
  --后用一些不那么重要的锦囊
  -- local id = hands[cpos]
  local card = hands[cpos]
  if card.type == Card.TypeTrick then
    local retfunc = LangAI.UseCardLogic[card.trueName]
    local ret = retfunc and retfunc(self,card) or nil
    if ret then
      return ret ~= 0 and ret or nil
    else
      return card
    end
  end
  return 
end

local handleChose = function (flag,target,player,num,self)
  local totalcards = target:getCardIds(flag)
  if #totalcards == 0 or num >= #totalcards then return totalcards end
  if LangAI.ISSAMECAMP(player,target) and string.find(flag,"j") and self.disFriendCard then
    local disarea_card = self.disFriendCard
    self.disFriendCard = nil
    return {disarea_card}
  end
  --优先选择装备
  local selcards = {}
  if flag == "e" or flag == "he" or flag == "hej" then
    local equips = target:getCardIds(Player.Equip)
    local hanlecards = function(area,remain)
      local newhands = target:getCardIds(area)
      if #newhands == 0 then return {} end
      for i = 1, remain do
        if #newhands == 0 then break end
        local rand = table.random(newhands)
        table.insert(selcards,rand)
        if num == #selcards then return selcards end
        table.removeOne(newhands,rand)
      end
    end
    if #equips == 0 and string.find(flag,"h") then
      hanlecards(Player.Hand,num)
      if num == #selcards then return selcards end
    else
      for _, subtype in ipairs(ImporEeuipsType) do
        for i = 1, #equips do
          local eid = equips[i]
          if not eid then break end
          local card = Fk:getCardById(eid)
          if card.sub_type == subtype then
            if subtype == Card.SubtypeDefensiveRide and player:distanceTo(target) ~= 1 then 
              table.insert(selcards,eid)
              table.remove(equips,i)
            end
            if subtype == Card.SubtypeWeapon and (not target:inMyAttackRange(player,-card.attack_range + 1) or DisEmyWeapons[card.trueName]) then 
              table.insert(selcards,eid)
              table.remove(equips,i)
            end
            if subtype == Card.SubtypeOffensiveRide and target:distanceTo(player) == 1 and player:getEquipment(Card.SubtypeDefensiveRide) then 
              table.insert(selcards,eid)
              table.remove(equips,i)
            end
            if subtype == Card.SubtypeArmor or subtype == Card.SubtypeTreasure then 
              table.insert(selcards,eid) 
              table.remove(equips,i)             
            end
          end
          if #selcards == num then return selcards end
        end
      end
    end
    if num - #selcards > 0 and string.find(flag,"h") then
      hanlecards(Player.Hand,num - #selcards)
      if num == #selcards then return selcards end
    end
    if num - #selcards > 0 and string.find(flag,"j") then
      hanlecards(Player.Judge,num - #selcards)
      if num == #selcards then return selcards end
    end
    return selcards
  else
    if flag == "h" then
      local newhands = target:getCardIds(Player.Hand)
      for i = 1, num do
        local rand = table.random(newhands)
        table.insert(selcards,rand)
        table.removeOne(newhands,rand)
      end
      return selcards
    end
    if flag == "j" then
      local newjudges = target:getCardIds(Player.Judge)
      for i = 1, num do
        local rand = table.random(newjudges)
        table.insert(selcards,rand)
        table.removeOne(newjudges,rand)
      end
      return selcards
    end
  end
end
--移动区域牌
random_cb.AskForMoveCardInBoard = function(self, jsonData)
  local data = json.decode(jsonData)
  local room = self.room
  local player = self.player
  if #data.cards == 0 then return "" end
  local playerIds = data.playerIds
  local friend = room:getPlayerById(playerIds[2]) --可能移动乐兵，是敌人
  local enemy = room:getPlayerById(playerIds[1]) --可能移动乐兵，是队友
  if not friend or not enemy then return "" end
  local carddatas = {}
  for _,cid in ipairs(data.cards) do
    local card = Fk:getCardById(cid)
    table.insert(carddatas,card)
    if card.sub_type == Card.SubtypeDelayedTrick and MoveDelaySeqs[card.trueName] and LangAI.ISSAMECAMP(room:getCardOwner(cid),player) then
      local mes = getJudegeData(enemy)
      if #mes > 0 then return json.encode{cardId = mes[2],pos = 0} end
    end
  end
  local sort_t = {}
  for _,t in ipairs(MoveEQSeqs) do
    for i,c in ipairs(carddatas) do
      if c.sub_type == t then
        table.insert(sort_t,c)
      end
    end
  end
  for _,c in ipairs(sort_t) do
    if not friend:getEquipment(c.sub_type) then
      return json.encode{
        cardId = c.id,
        pos = 0
      }
    end
  end
  return ""
end
--选择别人的单卡
random_cb.AskForCardChosen = function(self, jsonData)
  local data = json.decode(jsonData)
  local room = self.room
  local player = self.player
  local tarid = data[1]
  local flag = data[2]
  local num = 1
  local skillname = data[3]
  local target = room:getPlayerById(tarid)
  if target then
    if type(flag) == "string" then
      if target:isNude() then
        return "__cancel"
      end
      local ret = handleChose(flag,target,player,num,self)
      if ret and #ret > 0 then
        return ret[1]
      end
      return ""
    else
      if flag.card_data[1] and flag.card_data[1][1] == "jiqiaos" then --激峭
        local cards_red,cards_black = {},{}
        for _,cid in ipairs(flag.card_data[1][2]) do
          local card = Fk:getCardById(cid)
          if card.color == Card.Red then
            table.insert(cards_red,cid)
          else
            table.insert(cards_black,cid)
          end
        end
        if target.hp < 2 and (#cards_black - #cards_red > 1 or #cards_red - #cards_black > 1) then return "__cancel" end
        local prioSelCard = function(prio_t)
          local ret = table.find(prio_t,function(cid) return target:canUse(Fk:getCardById(cid)) end)
          return not ret and getSelCardsSeq(prio_t,1,selcards_prio_t)[1] or ret
        end
        if not target:isWounded() then
          return prioSelCard(table.clone(flag.card_data[1][2]))
        else
          return #cards_black >= #cards_red and prioSelCard(cards_black) or prioSelCard(cards_red)
        end
      end
      local handcards = {}
      for _, t in ipairs(flag.card_data) do
        table.insertTable(handcards, t[2])
      end
      if #handcards == 0 then return "__cancel" end
      return handcards[math.random(1, #handcards)]
    end
  else
    return "__cancel"
  end
end
--选择别人的多卡
random_cb.AskForCardsChosen = function(self, data)
  local player = self.player
  local room = player.room
  -- local data = json.decode(jsonData)
  local extra_data = data.extra_data
  local tarid = extra_data.to
  local max = extra_data.max
  local flag = ""
  if type(data.data[1][1]) == "string" and string.startsWith(data.data[1][1],"$") then
    for _,st in ipairs(data.data) do
      if st[1] == "$Hand" then flag = flag + "h" end
      if st[1] == "$Equip" then flag = flag + "e" end
      if st[1] == "$Judge" then flag = flag + "j" end
    end
  else
    flag = data.data
  end
  if flag == "" then return "__cancel" end
  local skillname = extra_data.skillName
  local target = room:getPlayerById(tarid)
  if target then
    if type(flag) == "string" then
      if target:isNude() then
        return "__cancel"
      end
      local ret = handleChose(flag,target,player,max,self)
      if ret and #ret > 0 then
        return json.encode(ret)
      end
      return ""
    else
      if type(flag) == "table" then
        if flag and #flag > 0 and skillname then
          local bottomcards = flag[1][2]
          if not bottomcards or type(bottomcards) ~= "table" or #bottomcards == 0 then return "" end
          local ret = {}
          if skillname == "cangxin" then
            ret = bottomcards
          end
          if skillname == "juetao" then
            ret = bottomcards
          end
          return #ret > 0 and json.encode(ret) or ""
        end
      end
    end
  end
  return "__cancel"
end
--卡牌选框逻辑（自定义）
-- {
--   data = { { { 902, 120, 820, 795, 813 }, {}, {} }, "#yuqi", 0, { 5, 1, 5 }, { 0, 1, 1 }, false, { "Top", "caojinyu", "caojinyu" }, ".", "", false },
--   path = "packages/utility/qml/ArrangeCardsBox.qml"
-- }
random_cb.AskForArrangeCards = function(self, jsonData)
  local player = self.player
  local room = player.room
  local data = json.decode(jsonData)
  local cards,prompt,cardsmes = data.cards,data.prompt,data.capacities
  if cards and prompt and prompt == "#yuqi" then
    cards = table.clone(cards[1])
    local getcards_damager = getSelCardsSeq(cards,1,discards_prio_t)
    local getcards_self = getSelCardsSeq(cards,math.min(cardsmes[3],#cards),selcards_prio_t)
    local ret = {cards,getcards_damager,getcards_self}
    return json.encode(ret)
  end
end
-- random_cb.CustomDialog = function(self, jsonData)
--   local player = self.player
--   local room = player.room
--   local data = json.decode(jsonData)
--   local data = data.data
  -- if eventdata and eventdata[3] and eventdata[3].name == "qianlong" then
  --   local ret = {{},{}}
  --   local max_top_cards = cardsmes[2]
  --   local linkskill = "juetao"
  --   local nouse_juetao = table.find(player.player_skills,function(s)
  --     if s.trueName == linkskill and player:usedSkillTimes(linkskill, Player.HistoryGame) == 0 then return true end
  --   end)
  --   local getcards = {"jink","nullification","collateral","analeptic","peach","supply_shortage","indulgence"}
  --   local slashs = {}
  --   local botomcards = table.clone(cards)
  --   for _,id in ipairs(cards) do
  --     local card = Fk:getCardById(id)
  --     if nouse_juetao and table.contains(getcards,card.trueName) then table.insert(ret[2],id) table.removeOne(botomcards,id) end
  --     if max_top_cards == #ret[2] then break end
  --   end
  --   local remain = max_top_cards - #ret[2]
  --   if remain > 0 then 
  --     if nouse_juetao then
  --       local slashs = {}
  --       for _,id in ipairs(botomcards) do
  --         local card = Fk:getCardById(id)
  --         if card.trueName ~= "slash" then table.insert(ret[2],id) else table.insert(slashs,id) end
  --         if max_top_cards == #ret[2] then break end
  --       end
  --       ret[1] = slashs
  --     else 
  --       for _,id in ipairs(cards) do
  --         table.insert(ret[1],id) 
  --         table.removeOne(botomcards,id)
  --         if max_top_cards == #ret[1] then break end
  --       end
  --       ret[1] = botomcards
  --     end
  --   end
  --   return json.encode(ret)
  -- end
-- end
--卡牌选框逻辑（观星）
random_cb.AskForGuanxing = function(self, jsonData)
  local player = self.player
  local room = player.room
  local data = json.decode(jsonData)
  local min_top_cards = data.min_top_cards
  local max_top_cards = data.max_top_cards
  local min_bottom_cards = data.min_bottom_cards
  local max_bottom_cards = data.max_bottom_cards
  local top_area_name = data.top_area_name
  local bottom_area_name = data.bottom_area_name
  local cards = data.cards
  local eventdata = room.logic:getCurrentEvent().data
  if eventdata and eventdata[3] and eventdata[3].name == "qianlong" then
    cards = cards[1]
    local ret = {{},{}}
    local linkskill = "juetao"
    local nouse_juetao = table.find(player.player_skills,function(s)
      if s.trueName == linkskill and player:usedSkillTimes(linkskill, Player.HistoryGame) == 0 then return true end
    end)
    local getcards = {"jink","nullification","collateral","analeptic","peach","supply_shortage","indulgence"}
    local slashs = {}
    local botomcards = table.clone(cards)
    for _,id in ipairs(cards) do
      local card = Fk:getCardById(id)
      if nouse_juetao and table.contains(getcards,card.trueName) then table.insert(ret[2],id) table.removeOne(botomcards,id) end
      if max_bottom_cards == #ret[2] then break end
    end
    local remain = max_bottom_cards - #ret[2]
    if remain > 0 then 
      if nouse_juetao then
        local slashs = {}
        for _,id in ipairs(botomcards) do
          local card = Fk:getCardById(id)
          if card.trueName ~= "slash" then table.insert(ret[2],id) else table.insert(slashs,id) end
          if max_bottom_cards == #ret[2] then break end
        end
        ret[1] = slashs
      else 
        for _,id in ipairs(cards) do
          table.insert(ret[2],id) 
          table.removeOne(botomcards,id)
          if max_bottom_cards == #ret[2] then break end
        end
        ret[1] = botomcards
      end
    end
    return json.encode(ret)
  end
  if min_top_cards == max_bottom_cards and min_bottom_cards == max_bottom_cards then
    local getcards = getSelCardsSeq(cards,2,selcards_prio_t)
    local ret = {getcards,cards}
    return json.encode(ret)
  end
  return  "__cancel"
end
--卡牌选框逻辑（五谷丰登）
random_cb.AskForAG = function(self, jsonData)
  local player = self.player
  local room = player.room
  local data = json.decode(jsonData)
  if data[3] == "amazing_grace_skill" then
    local cards = data[1]
    local getcard = getSelCardsSeq(cards,1,selcards_prio_t)
    if #getcard > 0 then
      return getcard[1]
    else
      return ""
    end
  end
end
--卡牌选框逻辑（破袭）
local handlePoxiSuit = function(whohands) --处理破袭花色
  local whosuits = {{},{}} --第1个空表是存已有花色，第2个是缺少的花色
  for _,cid in ipairs(whohands) do
    local card = Fk:getCardById(cid)
    if not whosuits[1][tostring(card.suit)] then
      whosuits[1][tostring(card.suit)] = cid
    end
  end
  if #whosuits[1] < 4 then
    for i = 1,4 do
      local inxstr = tostring(i)
      if not whosuits[1][inxstr] then
        whosuits[2][inxstr] = i
      end
    end
  end
  return whosuits
end
local handlepoxiCode = function(whosuits) --处理发送的破袭花色id数据
  local ret = {}
  for i, v in pairs(whosuits) do
    table.insert(ret, v)
  end
  return #ret == 4 and ret or nil --不满足四花色就取消
end
random_cb.AskForPoxi = function(self, jsonData)
  local player = self.player
  local room = player.room
  local data = json.decode(jsonData)
  if data.type and data.type == "AskForCardsChosen" then
    return self.cb_table[data.type](self,data)
  end
  local poxidata = data.data
  local playerhands = player.player_cards[Player.Hand]
  local enemyhands = poxidata and poxidata[2] and poxidata[2][2]
  if not enemyhands or #enemyhands == 0 then return "__cancel" end
  local playersuits = handlePoxiSuit(playerhands)
  local enemysuits = handlePoxiSuit(enemyhands)
  local hdlfillsuit = function(onesuits,twosuits) --第一个参数是敌人手牌花色表，缺什么花色能补就从第2个ai手牌表参数补
    for suit,suit_v in pairs(onesuits[2]) do
      if twosuits[1][suit] then
        onesuits[1][suit] = twosuits[1][suit]
      end
    end
  end
  local discardfill = function(discardsuits,fillsuits) --给第一个参数的花色数拆1补1
    local prhavesuits = fillsuits[1]
    local dishavesuits = discardsuits[1]
    local disnosuits = discardsuits[2]
    if next(disnosuits) then
      local fillsuitids = {}
      for s,v in pairs(disnosuits) do
        if prhavesuits[s] then fillsuitids[s] = prhavesuits[s] end
      end
      for s,v in pairs(prhavesuits) do
        if dishavesuits[s] then fillsuitids[s] = v break end
      end
      for s,v in pairs(fillsuitids) do
        dishavesuits[s] = v 
      end
      local ret = handlepoxiCode(discardsuits[1])
      if ret then return json.encode(ret) end
    else
      local id = prhavesuits["1"] or prhavesuits["2"] or prhavesuits["3"] or prhavesuits["4"]
      if id then
        local card = Fk:getCardById(id)
        local subsuit = card.suit
        discardsuits[1][tostring(subsuit)] = nil
        discardsuits[2][tostring(subsuit)] = 1
        hdlfillsuit(discardsuits,fillsuits)
        local ret = handlepoxiCode(discardsuits[1])
        if ret then return json.encode(ret) end
      end
    end
  end
  --拆ai牌
  local pn = LangAI.CNTTNUM(playersuits[1])
  if pn >= 3 and player.hp < 3 then --ai有四花色情况下，ai血量过低优先拆敌3牌
    if pn == 3 then
      hdlfillsuit(playersuits,enemysuits)
      local ret = handlepoxiCode(playersuits[1])
      if ret then return json.encode(ret) end
    else
      local result = discardfill(playersuits,enemysuits)
      if result then return result end 
    end
  end
  --拆敌人牌
  local en = LangAI.CNTTNUM(enemysuits[1])
  if en ~= 3 then --尽量避免拆敌人牌3花色
    if en == 1 and pn == 3 and (player.hp == player.maxHp or #playerhands < 9) then --极端情况下点取消
      return "[]"
    end
  else
    if #playerhands > 2 then  --如果牌多互拆2-2花色，牌少就不22，尽量能拆敌3己1
      local result = discardfill(enemysuits,playersuits)
      if result then return result end 
      return "[]" 
    end
  end
  hdlfillsuit(enemysuits,playersuits)
  local ret = handlepoxiCode(enemysuits[1])
  if ret then return json.encode(ret) end
  return "[]"
end
---@param self LangAI
--出牌阶段使用卡牌
random_cb.PlayCard = function(self, jsonData)
  local player = self.player
  player.room.room_settings = player.room.settings
  local UseCardTrack = function ()
    local history_slash = player:usedCardTimes("slash",Player.HistoryPhase)
    if self.upmaxslash then upSkillsInfo(self) end --刷新ai技能信息和最不想针对技能目标角色（卖血技能如遗迹）
    self:UpFilterSkills() --刷新ai视为技能
    self.handcards = {}
    self.jumpcards = {}
    for _,cid in ipairs(player.player_cards[Player.Hand]) do
      local card = Fk:getCardById(cid,true)
      card = CardFilterHandle(player,card,self.fiterskills)
      if player:canUse(card) then table.insert(self.handcards,card) end
    end
    
    local remainslash = self.totalslash and self.totalslash - history_slash or 1
    self.reslash = remainslash
    local skills = player.player_skills
    if #self.handcards > 0 then
      for i = 1, #self.handcards do
        local usecard = upUseCardsSeq(self,i,remainslash) -- 检测手牌可以使用打出
        if usecard then
          local ret = PlayCards(self,usecard.skill,usecard)
          if ret then 
            return ret 
          else
            self.jumpcards[usecard.name] = true
          end
        end
      end
    end
  end
  --出牌前优先使用技能
  local useskillpri = table.find(player.player_skills,function (s)
    if LangAI.USESKILLPRIO[s.trueName] and not LangAI.BLACKSKILLS[s.trueName] and not self.activeJumps[s.name] and not LangAI.USESKILLBYPLAY.analeptic[s.trueName] then
      if s:isInstanceOf(ActiveSkill) then
        return s.canUse and s:canUse(player)
      elseif s:isInstanceOf(ViewAsSkill) then
        return s.enabledAtPlay and s:enabledAtPlay(player)
      end
    end
  end)
  if useskillpri then
    if useskillpri:isInstanceOf(ActiveSkill) then
      local ret
      if not singleOptiSkill[useskillpri.name] then
        ret = useActiveSkill(self, useskillpri, nil)
      else
        ret = singleOptiSkill[useskillpri.name](self,useskillpri)
      end
      if ret then return ret end 
    elseif useskillpri:isInstanceOf(ViewAsSkill) then
      local ret = useVSSkill(self, useskillpri, nil)
      if ret then return ret end 
    end
  end
  --检测使用卡牌
  local useret = UseCardTrack()
  if useret then return useret end
  --检测技能，避免有些技能卡住死循环
  if self.usedskill >= 10 then
    self.usedskill = 0
    self.activeJumps = {}
    return ""
  end
  local actives_vss = table.filter(player.player_skills, function(s)
    return s:isInstanceOf(ActiveSkill) and s.canUse and s:canUse(player) and not self.activeJumps[s.name] and not LangAI.BLACKSKILLS[s.trueName]  
  end)
  local vss = table.filter(player.player_skills, function(s)
    if s.name == "spear_skill" and #self.handcards < 2 then --不写enabledAtPlay的后果
      return false
    end
    return s:isInstanceOf(ViewAsSkill) and s.enabledAtPlay and s:enabledAtPlay(player) and not LangAI.BLACKSKILLS[s.trueName]
  end)
  table.insertTable(actives_vss,vss)
  -- 
  if #actives_vss > 0 then
    local reusecard = false
    local sth =table.remove(actives_vss,1)       
    if #actives_vss == 0 then reusecard = true end
    if sth:isInstanceOf(ActiveSkill) then
      local ret
      if not singleOptiSkill[sth.name] then
        ret = useActiveSkill(self, sth, nil)
      else
        ret = singleOptiSkill[sth.name](self,sth)
      end
      if ret then return ret else self.activeJumps[sth.name] = true end
    else
      local ret = useVSSkill(self, sth, nil)
      if ret then return ret else self.activeJumps[sth.name] = true end
    end
    if reusecard then 
      local ret = UseCardTrack(self,jsonData)         
      if ret then return ret end
      return ""
    end
    --如果还有技能就递归  
    self.usedskill = self.usedskill + 1  
    self.cb_table[self.command](self,jsonData)
  end
  self.usedskill = 0
  self.activeJumps = {}
  return ""
end

function LangAI:UpFilterSkills()
  local skills = self.player.player_skills
  self.fiterskills = {}
  for _, s in ipairs(skills) do
    if s:isInstanceOf(FilterSkill) then
      table.insert(self.fiterskills,s)
    end
    for i, rela_s in ipairs(s.related_skills) do
      if rela_s:isInstanceOf(FilterSkill) then
        table.insert(self.fiterskills,rela_s)
      end
    end
  end
end




function LangAI:initialize(player)
  AI.initialize(self, player)
  self.handcards = {}
  self.usedskill = 0      --使用技能次数（预防有的主动技能可以一直使用死循环）
  self.activeJumps = {}   --主动技能跳过列表（如果技能发动但是因为某些条件限制没有效果下一次就跳过发动）
  self.upmaxslash = true  --刷新能够使用杀总次数
  self.totalslash = 1     --使用杀总次数
  self.fiterskills = {}   --视为卡牌技能根据人机是否有视为技来给卡牌视为效果
  self.weekAtkPids = {}   --弱化进攻这个列表里的玩家id
  self.jumpcards = {}     --使用打出卡牌受到禁止技能或者距离不够等限制就跳过使用这张卡使用下一张卡
  self.repequip = false   --替换装备

  self.cb_table = random_cb
end

return LangAI
